Welcome back. This set of lessons introduces race conditions and describes how having two or more seemingly simultaneous sets of commands can cause conflicting instructions in your programs. This affects the program's efficiency and security, as well as systems security. We will discuss how you can prevent race conditions for happening, and identify them when they do. Let's get started. So this lesson is on race conditions. Now, a race condition essentially is two processes trying to do something, and the order of the processes in which the process is trying to do it affects the result. Now, I'm going to focus in this lesson on what are known as time of check to time of use race conditions and these involve files. We'll talk about how to spot them, how to prevent them, and so forth. Then towards the end, we'll talk about other types of race conditions that can occur when you're doing multithreading or handling asynchronous events. Now, if you look at the next slide, two events, a and b are going to occur. The question is, in what order? Normally, if order doesn't matter, then there is no possibility of security problem unless together they form a security problem which we'll assume they don't. But if order matters, one order may be fine, the other order may create a security problem. The reason it's called a race condition is because the order matters, so both processes are racing to do something. The question is, who wins the race? Who does it first? Now, the one thing about a race condition is it always involves two processes or two threads. A single process or a single thread will never have a race condition in and of itself. But if that process is running, then a second process starts up and tries to interfere with the first. You may have a race condition. By the way, throughout this lesson, I'm going to use the term process. This also applies to multithreading. So if you like, you should treat processes also a thread. Basically, any type of concurrent programming or concurrent processes can cause this issue. A thread really use is a, if you like, a lightweight process. Now, let me give you an example that will show you how race conditions arise. This is a very simple example from a particular version of Sendmail, which ran sit you idea roots. So it rain with root privileges. Sendmail is a very complex program, and its configuration file is also very complex. It's designed to be read quickly by computers. But that means humans often make errors when setting it up. So the author of Sendmail, Erica Baum very kindly provided a dash C option, capital C option to allow you to test Sendmail. It would essentially load the configuration file and let you try various things to see whether or not you had it configured correctly. Now initially, you could give it the name of any file. Since Sendmail ran setuid to root, you would give it a file that was not a configuration file. Because this was intended to debug config files, the air messages at gave were superb, including it would print out the line and then print out a message challenge you what was wrong with the line. So if you go to the slide that's Sendmail attack, when you ran Sendmail with the configuration file of some protected file that you normally couldn't read. Sendmail would open the file since it's running as root, and read the first line and say, "Well, wait a minute. That's not a proper configuration line." So it will simply print the line and then print an error message like bad format or something. You can see a couple of examples there. This is the beginning of the Declaration of Independence. In this case, when in the course of human events is not a valid configuration line and so forth. So what you would do, is ran this on any file you liked and get the output and then delete every other line beginning with the second, and now you have the file. Now, in a sense this is a, you're giving too much information on an error. This is not the race condition. But the way you fix it can introduce a race condition. Because the problem here is that Sendmail is setuid to root, so it can open any file. But if the real user ID, the person who is running it as not root, Sendmail should only open those files which that user can open. So we have conflict here between the RealUID which is root and the effect of UID which is the UID of the person running Sendmail. So somehow you have to figure out how to handle that. The next slide shows the Obvious Fix. There is a system called access. What that says is, "Give me the config file and the way you want to open it: read, write, a patent, whatever execute whatever, as the second document." If the user with the effect of UID of the current process can open that file in that way, it returns zero, otherwise it returns negative one. So the access system call is given right up there. You do the test and if it returns zero, then you go ahead and open the config file. Problem is the solution is attractive as it is as flawed. If you look at the next line, you'll see an example. The code there is the typical use of access. But here is the problem, notice in both lines, it's referring to the file by name. So what that means is, in order to locate the file, it has to go into the kernel and resolve that name turning it into an inode, turn it into a position on disk. So the access cause issue that does that first with xyz. But then when fopen is issued, it does the same thing. Now, the results may be cached from the first one. So it may be very quick the second time. But the point is, both times it's doing that resolution. So here's the problem. What happens if I change the reference of xyz? If it's not cached, then it'll do the normal search and want to do the open, I'll get the new one. If it is cached, well, then there'll be a mismatch between what's in the cache and what the actual content of disk is and so the cash will be ignored. So in this case, the problem is initially xyz points to something that I can read. But between the access and the fopen, I delete that link and recreate xyz. But instead of creating the file, actually link it to something that only root can read. So in essence what's happening is, I'm opening a different file than the one I checked. So the check becomes completely irrelevant. That's a race condition, because you have this window between access and fopen where I can change what the check is validating. So the check validate something correctly. But I don't care because the open refers to something completely different.