tmpwatch race condition vulnerability to clean any directory

Wojciech Purczynski cliph at isec.pl
Tue Mar 12 00:02:38 CET 2002


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


Name:		tmpwatch
Version:	2.6.1-3
Vendor:		PLD
Author:		Wojciech Purczynski (cliph at isec.pl)
Date:		March 11, 2002


Issue:
======

Tmpwatch race condition vulnerability allows local non-privileged users to
delete content of any directory in the file system.


Description:
============

Tmpwatch is a utility for removing files based on when they were last
accessed. It is commonly used to perform periodical cleaning of /tmp and
other world-writable directories.


Details:
========

Tmpwatch contains race condition and insecurely travels across directory
tree which may be easily tricted to go into arbitrary directory in order
to perform its primary task - clean directory of files that were not been
used for a some period of time. As this utility is often run by UID 0 from
cron daemon once per day, the race condition vulnerability may allow local
non-privileged users to remove content of *any* directory in the file
system.

If the directory tmpwatch wants to clean does have some subdirectiories,
it goes to the subdirectory and cleans it recursively. Cleaning of
/tmp/a/b/[cd] directory structure looks like:

(strace output somewhat simplified and reformatted)

chdir("/tmp")                           = 0
open(".", O_RDONLY)                     = 4
chdir("/tmp/a")                         = 0
  open(".", O_RDONLY)                     = 6   /* /tmp/a */
  chdir("/tmp/a/b")                       = 0
    open(".", O_RDONLY)                     = 8 /* /tmp/a/b */
    chdir("/tmp/a/b/c")                     = 0
      /* directory is empty */
    fchdir(8)                               = 0 /* back to /tmp/a/b */
    rmdir("c")                              = 0
    open(".", O_RDONLY)                     = 8 /* /tmp/a/b */
    chdir("/tmp/a/b/d")                     = 0
      /* directory is empty */
    fchdir(8)                               = 0 /* back to /tmp/a/b */
    rmdir("d")                              = 0
  fchdir(6)                               = 0   /* back to /tmp/a */
  rmdir("b")                              = 0
fchdir(4)                               = 0     /* back to /tmp */
rmdir("a")                              = 0

After the cleaning of content of the bottom directory /tmp/a/b/c is
completed tmpwatch goes to the upper directory /tmp/a/b. Then it goes to
the /tmp/a/b/d directory to perform cleaning operation in it.

If we take a close look at the strace output on how tmpwatch changes the
directory we will see that this operation is done insecurely:

(strace output abbreviated)

chdir("/tmp/a/b")                       = 0
open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY) = 7
getdents(7, /* 4 entries */, 3933)      = 52
lstat("c", {st_mode=S_IFDIR|0755, st_size=4096, ...})
open(".", O_RDONLY)                     = 8
lstat("/tmp/a/b/c", ...)                = 0
chdir("/tmp/a/b/c")                     = 0
/* cleaning of /tmp/a/b/c directory */
fchdir(8)                               = 0
close(8)                                = 0
rmdir("c")                              = 0
lstat("d", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open(".", O_RDONLY)                     = 8
lstat("/tmp/a/b/d", ...)                = 0
chdir("/tmp/a/b/d")                     = 0
/* and so on... */

Between chdir("/tmp/a/b/c") and chdir("/tmp/a/b/d") we have a race
condition. We may create symlink to the arbitrary directory in place of
/tmp/a/b that we may just rename. Tmpwatch will follow symlink inside of
directory path and will perform its task in the directory it will be
directed to.

Timeframe between those chdirs may be very long because it depends on how
much time tmpwatch will spend cleaning of big number of files inside
/tmp/a/b/c directory.

The problem exists because tmpwatch does depend on its own directory path
stored in memory variable and changes directories using absolute path
names.

We have created proof-of-concept exploit, although we are not going to
publish it until this nasty bug is fixed.

The possibility of deleting content of any directory in the file system
may lead to root compromise in some rare circumstances.


Fix:
====

It has been fixed a long time ago in other distros.


- ---
Wojciech Purczynski
iSEC Security Research
http://isec.pl/

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

iD8DBQE8jTecC+8U3Z5wpu4RAncdAKDKI4t+ZzOfD2smgZRdIq0jLmOrIgCfXmsN
AFA7DirsK8pjdu2pqfctFRk=
=Ii9W
-----END PGP SIGNATURE-----




More information about the feedback mailing list