On 27 Nov 1999 23:05:19 +0100, Tollef Fog Heen <tollef add no> wrote:
>Wade Maxfield <maxfield ctelcom net> writes:
>> If a perp can create a symlink to a file that a daemon is
>> about to delete (such as in a tmp directory), he may get /etc/hosts.deny
>> deleted through the daemon not checking.
>
>Please note that according to:
>UNLINK(2) Linux Programmer's Manual UNLINK(2)
>
>unlink does _not_ follow symlinks:
>
> If the name referred to a symbolic link the link is
> removed.
>
>So, using unlink on a symbolic link is _not_ harmful.
This is not entirely accurate.
In fact, unlink _does_ follow symlinks, if the symlinks are directory
components of the parameter to unlink. So for example, if I do:
ln -s /etc /tmp/foo
then if root can somehow be tricked into executing:
unlink("/tmp/foo/passwd")
you will find you no longer have /etc/passwd, because unlink() followed
a symlink.
The correct way to unlink files with untrusted directory components in
the filename is to start at the last trustworthy component (or "/" if
you don't trust any components), and individually chdir() and through
all the remaining components, verifying using lstat() that you have not
followed a symlink with chdir().
Deleting files in /tmp (or a user's home directory, for that matter)
is not a trivial operation from a security point of view. You can't
safely use "find" and "xargs"--or even "rm -rf"--unless you can guarantee
that no users have write access to the directory tree in question
(e.g. because the system is in single-user mode).
The "tmpreaper" package in Debian does this correctly (and they even
indirectly credit me in the sources with a URL pointing to an article
I wrote on the subject).
>If this thing is going to be programmed in C, the "correct" way to
>create a file is:
>
>open("filename",O_CREAT|O_EXCL|O_WRONLY,whatever_permissions_you_want);
The same applies here too. Imagine:
ln -s /home/victim /tmp/bar
followed by
open("/tmp/bar/.rhosts", O_CREAT|O_EXCL|O_WRONLY...)
This will succeed in creating /home/victim/.rhosts provided that
it did not exist before.
>(change O_WRONLY to O_RDWR if you want to read from the file)
>
>Please note that this is _not_ secure over NFS (as the man 2 open page
>says), but there is another way (see open(2) man page).
_Nothing_ is secure over NFS if the server or network can be compromised.
Again, an attacker can cause fairly large amounts of damage by forcing
the victim to follow symlinks in directory components of filenames.
>To open an existing file you can do:
>
>open("filename",O_RDWR|O_NOFOLLOW);
>
>This requires kernel 2.1.126 and glibc >= 2.0.100.
Now _this_ is cool. Does this also work on directory components, and
is there a way to make it work with unlink(), rename(), and friends?
>Else you can use
>lstat("filename", statbuf_1);
>fd = open("filename", O_RDWR);
>fstat(fd,statbuf_2);
>
>if (stabuf_1.ino_t != statbuf_2.ino_t) /* differing inode? */ {
> log_this_error;
> exit_gracefully_or_error_recovery;
>}
Don't forget close(fd)!
>Of course, the proper way to do this is a non-shared tmp
>directory.
True. Wherever possible, do not use /tmp at all. If you have a daemon,
set up a /var/run, /var/state, or /var/cache directory (see the FHS at
http://www.pathname.com/fhs/) and make your daemon use that. Give the
daemon its own non-root user ID so that even if it is compromised, it
can't affect other daemons without cracking root first.
Shared /tmp combined with symlinks and the existing Unix filesystem API
is a singularly braindead concept, but one we must unfortunately live
with because this bug has two decades of seniority and counting...
>This can also be done using a mkdir in /tmp. mkdir does not
>follow dangling symlinks.
mkdir() is also an NFS-safe locking mechanism, too--CVS uses it.
Of course this only works if you mkdir "/tmp/fooXXXXXX" and not mkdir
"/tmp/foo/barXXXXXX".
--
I don't speak for Corel. zygob corel ca at work, zblaxell furryterror org
at play. GPG-encrypted email preferred at zblaxell feedme hungrycats org
GPG fingerprint: 2B32 546D 21A5 0DB2 20C8 AF10 1D4A 610E 6972 2DEE
GPG public key: http://www.hungrycats.org/~zblaxell/gpg-public.txt
Attachment:
pgp00000.pgp
Description: PGP signature