[14837] in bugtraq
Re: Race condition in "rm -r"
daemon@ATHENA.MIT.EDU (Alex Belits)
Mon May 8 14:51:44 2000
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
Message-Id: <Pine.LNX.4.20.0005071248270.8241-100000@phobos.illtel.denver.co.us>
Date: Sun, 7 May 2000 13:03:28 -0700
Reply-To: Alex Belits <abelits@PHOBOS.ILLTEL.DENVER.CO.US>
From: Alex Belits <abelits@PHOBOS.ILLTEL.DENVER.CO.US>
X-To: Glynn Clements <glynn@SENSEI.CO.UK>
To: BUGTRAQ@SECURITYFOCUS.COM
In-Reply-To: <14612.37604.614357.770670@cerise.sensei.co.uk>
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