Way to stop /tmp races

Pavel Machek (pavel@ELF.UCW.CZ)
Sat, 21 Mar 1998 20:37:10 +0100

Hi!

Maybe I have a way to stop /tmp races, at expense of relatively small
semantic change. Trick is to modify open() to force O_EXCL if it is
under /tmp. Code follows, it is pretty short.

Share and enjoy,

Pavel
PS: Special question for solar designer:
You have patch for similar purpose, but it was kernel patch. How did
you solve:

A: (victim) B: (attacker)
> /tmp/file
chmod 666 file
writes data to /tmp/file
closes /tmp/file
changes data in /tmp/file
reads back spoofed data

? [Sorry if it is stupid question.]

PPS: This is linux-specific, but at least like libc change it can be
done on any unix I know of.

/*
* Ok, we'll close some of those nasty /tmp races.
*
* Copyright 1998 Pavel Machek <pavel@ucw.cz>,
* distribute under General Public License, version 2
*
* To use: gcc safetmp.c -shared -o libsafetmp.so
* then either export LD_PRELOAD=/full_path/libsafetmp.so
* or if you are root and *DARING*
* echo "/full_path/libsafetmp.so" > /etc/ld.so.preload
*
* Version 0.0.1. Should work on Linux, should be possible to make it
* work on other systems.
*/

#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <syslog.h>

int
open( const char *pathname, int flags, ... )
{
int ret;
const char *s;
mode_t mode = 0;
va_list ap;
va_start( ap, flags );

if (flags & O_CREAT)
mode = va_arg( ap, mode_t );

s = pathname;
if (*s == '/') {
while( *s == '/' )
s++;
if ((!strncmp( s, "tmp/", 4)) &&
((flags & (O_CREAT|O_TRUNC)) == (O_CREAT|O_TRUNC)) &&
(!(flags & O_EXCL))) {
syslog( LOG_INFO, "Insecure open: %d tries to open(%s,%d,%d)\n", getpid(), pathname, flags, mode );
unlink( pathname );
flags |= O_EXCL;
}
}

return __open( pathname, flags, mode );

va_end( ap );
return ret;
}

--
I'm really pavel@atrey.karlin.mff.cuni.cz.         Pavel
Look at http://atrey.karlin.mff.cuni.cz/~pavel/ ;-).