Bugtraq mailing list archives

Re: Race condition in "rm -r"


From: abelits () PHOBOS ILLTEL DENVER CO US (Alex Belits)
Date: Sun, 7 May 2000 13:03:28 -0700


On Sat, 6 May 2000, Glynn Clements wrote:

Use a statically-linked "rm" and "chroot /tmp" first.

  Maybe stat "." after chdir to verify that we ended up the
  expected place?

  More like;y getcwd() will be useful -- there is nothing in stat that can
tell us if we followed a link, and inode comparison may be unreliable.


My "rm" (GNU fileutils 4.0) does this:

    getdents(3, /* 45 entries */, 3933)     = 924
    lstat("Imakefile", {st_mode=S_IFREG|0644, st_size=2842, ...}) = 0
    unlink("Imakefile")                     = 0
    lstat("pixmaps", {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
    chdir("pixmaps")                        = 0
    close(3)                                = 0
1>  open(".", O_RDONLY|O_NONBLOCK)          = 3
    fcntl(3, F_SETFD, FD_CLOEXEC)           = 0
2>  fstat(3, {st_mode=S_IFDIR|0755, st_size=1024, ...}) = 0
    lseek(3, 0, SEEK_CUR)                   = 0
    getdents(3, /* 49 entries */, 3933)     = 1112
    lstat("about.xpm", {st_mode=S_IFREG|0644, st_size=43055, ...}) = 0
    unlink("about.xpm")                     = 0
    lstat("apple.xpm", {st_mode=S_IFREG|0644, st_size=927, ...}) = 0
    unlink("apple.xpm")                     = 0

Any suggestions as to why it is doing the fstat() in (2) if it isn't
checking for symlink games? [Note: I'm not saying that it *is*
checking, just that it seems odd if it isn't.]

  Relevant piece from glibc 2.1.1 opendir() (other libraries probably do
something similar):

---8<---
    {
      /* We first have to check whether the name is for a directory.  We
         cannot do this after the open() call since the open/close operation
         performed on, say, a tape device might have undesirable effects.  */
      if (__xstat (_STAT_VER, name, &statbuf) < 0)
        return NULL;
      if (! S_ISDIR (statbuf.st_mode))
        {
          __set_errno (ENOTDIR);
          return NULL;
         }
    }

  fd = __open (name, O_RDONLY|O_NDELAY|EXTRA_FLAGS);
  if (fd < 0)
    return NULL;

  /* Now make sure this really is a directory and nothing changed since
     the `stat' call.  */
  if (__fstat (fd, &statbuf) < 0)
    goto lose;
  if (! S_ISDIR (statbuf.st_mode))
    {
      save_errno = ENOTDIR;
      goto lose;
    }

  if (__fcntl (fd, F_SETFD, FD_CLOEXEC) < 0)
    goto lose;
--->8---

  (lines before open() don't exist in your example, however I have left
them because otherwise comment for fstat() doesn't make sense).

--
Alex

----------------------------------------------------------------------
 Excellent.. now give users the option to cut your hair you hippie!
                                                  -- Anonymous Coward



Current thread: