O_CREAT
and O_EXCL
when opening the file. It is then it is possible for a malicious user
to compromise the account of the person who creates the files in
/tmp. This includes the root account, since programs like sort and vi
have this bug.
Another misfeature is that programs create temporary files without the user being aware of it. Consequently, it may be that a program reveals private data from a non-world-reabable directory by copying the data into /tmp (and honouring the user's umask).
It is impracticable to replace all programs that have this bug,
and the bug is really a more fundamental design problem with /tmp. The
fact that /tmp is a shared directory leads to most of the problems. A
partial solution is to replace the shared /tmp with a copy of /tmp for
each user. Some files won't fit in with the scheme because they don't
belong to any user, for example, the X11
directories. .X11-unix
should be moved out of /tmp anyway
to avoid cookie interception, and .X11-lock
should be
moved out to avoid a denial of service attack against the X-server.
Similar arguments can be used to justify moving other shared files out
of /tmp.
Originally, I had thought of having the temporary directory depend on the uid (or fsuid) of the reading process. This leads to confusion with programs that use seteuid to change between root and another user. It also produces surprising results if a user passes a setuid program a filename in /tmp. Rather than having the temporary directory depend on a uid, I decided to make it a property of a tree of processes, so the location of /tmp is set by the login program, and is inherited by child processes, analogous to the way that the root and working directories are handled.
To implement this, I added a chtmp
system call. Since the
behaviour of setuid programs can be altered using this system call, I
made the system call require the chroot capability. The real location
of /tmp is then visible in /proc, as a pseudo-symlink. (It's not a
real symlink since it you don't require access to the parent
directories of the target of the link in order to follow the link.)
To start using the chtmp mechanism, the filename /tmp is made to be a
symlink to /proc/self/tmp, so that changing directory to /tmp changes
to the temporary directory for that process. init is started with '/'
as its temporary directory. I added a chtmp program, which is just
like chroot, and started all of init's children using this program,
setting /tmp to /temp/root.
Only root has access to root's temporary directory, so when a program
changes user, it needs to change temporary directory too. Identifying
such programs isn't too difficult - to change user, a program must be
running as root, or be setuid root. To locate the programs, use
find -perm -04000
, and look in
/etc/inittab
, /etc/init.d/*
,
/etc/inetd.conf
and /etc/cron.*/*
. If a
program is missed, the chances are that the program will stop working
alogether rather than start producing incorrect output since it won't
be able to write to /tmp. In addition, since .X11-unix
has moved, the X libraries and some programs will need modification.
I identified the programs that change user as:
The new structure for /tmp is:
/temp |`---- root |`---- nobody |`---- X | |`---- X11-unix/X0 | |`---- X11-unix/X1 | `---- X0-lock |`---- user1 |`---- user2 `---- user3 [etc] /tmp -> /proc/self/tmpThe permissions of the user temporary directories are
drwx-----T
. The sticky bit is there simply to keep sshd
quiet. Since sshd requires the sticky bit, I also use it to notice
when directory creation is complete. (Creating the directory involves
mkdir, chown and chmod, which cannot be made atomic; I regard the
process as complete after the chmod.)
int mkusertemp(const char *user, uid_t uid, gid_t gid);Since the application program has typically just done a getpwnam to find which user to change to, I don't bother doing the lookup in the library. This function creates the temporary directory and chtmp()s to it.