I wanted to close with a puzzle, and here's the puzzle.
There was a program called Mathematica,
that does advanced mathematics and it
turns out it creates temporary files
in a directory /tmp/MathLink.
It just creates those files
and overwrites existing ones in the directory.
The first question is,
how would you exploit this to
clobber someone's start-up file?
I'll give you a minute to think about that.
Remember the goal here is to
overwrite someone else's file.
The blue code beneath the question shows you this.
You create a directory called MathLink, which you own.
Then you do a symbolic link
to one of the files that you know will be created there.
If it's on the same file system,
you could make the link direct not symbolic.
Anyway, then when Mathematica runs,
it's going to open that file.
It will do so because on some systems it is
root privileges just overwrite what it's in the.gshmm,
which will overwrite what's in
the cshrc file, so you're done.
Now the next puzzle is how would you fix this?
I might give you a minute to think about that.
There are two ways to fix this.
The hard way is to check that
the file is in fact owned by a root or
owned by whoever is running Mathematica.
I did in the example I gave earlier.
What will happen is no it's
not because it's owned by a victim.
A second way to handle this which is actually much
cheaper, it's just delete the file.
If a file exists and Mathematica wants to write it,
delete the existing one.
It's an old file, it's just lying
around there not doing anything.
If you delete it, you're not
going to delete the victim start-up
file because that's a link.
What's in the MathLink directory is a link to that file,
so you just delete it.
By the way, when you do this if it's a symbolic link,
make sure you delete the symbolic link
and not the referent.
On all systems that I know of,
Linux and FreeBSD for example,
unlink will actually unlink the symbolic link
but double-check your manual and that solves the problem.
So this leads to two key ideas.
Probably the most fundamental is that
a race condition requires two processes.
No single process can ever have a race condition,
it requires two processes, two threads, whatever.
It also requires that the environmental condition holds,
so it's not just the property of the process,
it's also a property of the environment
in which the process runs.
The programming condition must hold within the process.
The other process has to hit
that window and do something within that window.
This by the way leads to the second observation which is,
when you're doing checking and then using,
check is close to the use as possible.
If you can do it in the same system call,
so much the better.
That's why when we talked about spawning subprocesses,
when the subprocess started up,
it had the effect of UID of
the real person who was running the program.
So the access check,
the appropriate access check is
performed in the open system call,
which for all intents and purposes is
indivisible with respect to this problem.
Within that window,
you want to make sure that the conditions
can't change and that's where
the environmental condition comes in.
Because that checks to see whether or not the
only ones who can make changes are trusted people.