Re: another /tmp race: `perl -e' opens temp file not safely

Theo de Raadt (deraadt@CVS.OPENBSD.ORG)
Sun, 08 Mar 1998 01:57:06 -0700

> homeok = ((home is writable for euid) and
> (home/tmp doesn't exist or is a dir writable for euid))
> groupok = (egid == gid) or (euid != uid)
> noprivs = (egid == gid) and (euid == uid)

Here we go again: this operation collects unreliable information.
Typical setuid processes can do significant amounts of uid
swaparounds, therefore this mechanism can be fooled quite simply by
the code which runs before it gets called. uid/euid and gid/egid
comparison does not work in all cases. Especially deep in libc.

This is why OpenBSD has the issetugid(2) system call; so that you can
determine if environment variables should be honoured deep down inside
libc, or other obscure places.

But the issue I am talking about is this: If you write fancy code
which decides to not to honour TMPDIR but use /tmp instead for that
temp file creation call, and the setuid process them creates that file
while it's euid is NOT the one which owns your hypothetical mode 644
/tmp, then it will fail to create it's file. In setuid processes,
mktemp can get done as either of the two uid's. It appears you have
not taken this into consideration at all. So your change will cause
security sensitive programs to start to fail in new ways which they
did not commonly fail in before.

Thus, /tmp must remain world writeable in ANY scenario.

I am getting quite tired of these suggested `tricks' which are clearly
not as good as auditing of the code, or which require the code to be
audited ANYWAYS. If you are going to audit it, you can use mkstemp()
*SAFELY* in every case. $TMPDIR doesn't solve all the problems!

(And I don't give a rat's ass about buggy mkstemp() implementations;
if those exist in some system there are likely 20 other bugs in that
system's libc, so to hell with those systems until they get audited
and FIXED. I do not write code workarounds for buggy libc code; the
libc code gets fixed).

Forthermore, what if a user points $TMPDIR at some mode 777 directory
(not 1777), and somehow convinces something else to put his files
there, now you have created whole new further problems. At least a
mkstemp() was safe because it was always in this nice 1777
directory... but now the user has created themselves a vulnerability.

> So, in practice, only setgid programs (because of the
> fact groups do not have homes) and third party stuff with hardcoded
> /tmp will be suspect. There is only a very limited number of setgid
> programs. And they all are in the OS so they can be audited.

Sigh. If they get audited, why not just make them use mkstemp(3) and
be done with the entire issue. I'm starting to think that the people
who post to bugtraq suffer from a serious case of Not Invented Here
syndrome; they all just want to tweak it in some unneccessary way; and
I will go out on the line and say that perhaps if they read more of
the code that uses these calls, and sat down and learned how to fix
150+ of these, they would decide that auditing and fixing code in the
ways which I have repeatedly proposed is actually damn easy.

You don't need a new strncpy().
You don't need a new strcpy().
You don't need a new routine for making temporary files.

You are never going to deploy those routines throughout all the source
code of the source tree _anyways_. Nobody is ever going to use your
non-standard routines.

If these newfangled solutions we hear on bugtraq are so wonderful, why
hasn't anyone put the work into a complete deployment of what they
suggest? (Put your money where your mouth is).

Now I've got nothing more to say on this topic; I'd rather go back to
auditing -- a process which seems to have worked far better than
Bugtraq solution-of-the-week.