MIT course "Computer Systems Security". Lecture 7: "Sandbox Native Client", part 1
Massachusetts Institute of Technology. Lecture course # 6.858. "Security of computer systems". Nikolai Zeldovich, James Mykens. year 2014
Computer Systems Security is a course on the development and implementation of secure computer systems. Lectures cover threat models, attacks that compromise security, and security methods based on the latest scientific work. Topics include operating system (OS) security, capabilities, information flow control, language security, network protocols, hardware protection and security in web applications.
Today we will talk about a system called Native Client , which Google uses in the real world. It is a sandbox technology for running code on different platforms. It is used in the Chrome browser , allowing web applications to run arbitrary machine code. This is actually a pretty cool system. It also illustrates the isolation capabilities and a peculiar sandbox or privilege separation method called “software failure isolation ,” software fault isolation , without using an operating system or virtual machine to create a sandbox. ')
Instead, the Native Client has a completely different approach to reviewing specific instructions in a binary file to find out if it will be safe to run or not. Therefore, before we begin to study the technical details of the system, let's find out why these guys really want to run the machine code? Their particular interest is in applying this solution in a web browser, where you can already run JavaScript code, Flash Player, and some other processes. Why are these guys so worried about the possibility of running code on the x86 platform? After all, it seems that this is a step back.
Audience: they want very fast calculations.
Professor: yes, this is one huge advantage of machine code. Even if it may be unsafe in the future, it does provide high performance. Everything that you wouldn’t do in JavaScript , for example, would write a program and compile it, it will actually work much faster. Are there any other reasons?
Audience: running existing code?
Professor: right. It is important that not everything can be written in JavaScript . So if you have an existing application, or, in industry terminology, “legacy” code that you are going to run on the Internet, this seems like a great solution. Because you can just take an existing library, for example, some complex graphic “engine”, which is both sensitive to performance and to many other complex things that you do not want to re-implement, and this will be a good solution. If you are just programming a new web application, should you use your own client if you are not particularly concerned about inheritance or performance?
Audience: then you don't need to use javascript .
Professor: yes, this is a good reason. If you don't like javascript , then you don't need to use it, right? You can use, for example, C , you can run Python code, write it in Haskell , in any language you think is more appropriate.
So, this is quite a convincing list of motivations for running your own code in the browser, while it is quite difficult to obtain the rights to such an action. Literally in a second we will look at technical details, and now I want to show you a simple training demo video that I received from the Native Client website.
It's pretty simple, because you can take C ++ or a C program and run it in a browser. You can look at this web page, which is an HTML file, inside which there is a bunch of JavaScript code.
The reason for the existence of this JavaScript code is that it allows you to interact with parts of the Native Client . Regarding the work of the browser, the meaning of this solution is that you have some kind of web page containing JavaScript code. And this solution works with the privileges of the pages and allows you to do various things on the web page itself, for example, to communicate with the network in some circumstances.
Native Client allows you to run your module inside the browser, so JavaScript code can interact with it and receive a response. This shows some of the JavaScript code that is required in the Native Client in order to interact with the specific NaCl module we are about to launch.
And you can send messages to this module. How it's done? You take the object of this module in JavaScript , call it postMessage and thus support sending this message to the NaCl module. When the NaCl module responds, it will start the message function in javascript . And in this particular case in the browser just pops up a dialog box.
So from the JavaScript side, this is a fairly simple web page interface. The only thing you need to do additionally is to assign the NaCl module in this way. That is, you simply insert a module with a specific ID here . The most interesting is hello code with the nmf extension. It simply says that there is an executable file that you need to download and start working with it in the NaCl environment.
This machine code is in fact similar to any other C ++ code you could write. An interesting part is this HandleMessage message handling function.
This is a C ++ class, and whenever JavaScript code sends some message to Native code, it will perform this function. It performs an if (message = = 'hello') check. If so, it will create a return line of some kind and send it back. This is pretty simple stuff. But for specifics, let's try to run it and see what happens.
We can build and run a small web server that will serve this page and the Native Client module. Here I can go to this URL , and here we see the NaCl web page. The module received our welcome message from JavaScript , responded back to the line in JavaScript , and the JavaScript code triggered a pop-up dialog box containing this response.
So it really works.
Try to find out if we can cause the Native Client to crash. I hope not, but we can take this code and this buffer and write a bunch of nonsense in it, for example, 65536 and see what happens.
I hope this should not cause my browser to crash, because the Native Client is trying to provide isolation. But let's see what happens.
Restart the web server. We see that the entrance to the module is still successful, our browser is not affected. However, the exchange of messages with the client did not take place, so the dialog box is missing. Let's look at the JavaScript console at the bottom of the page and see that the Native Client module informs us about the failure of the NaCl module.
It is possible that the argument I entered caused a buffer overflow or a call to some wrong address, but in any case, the NaCl module is really able to isolate accidental memory damage in such a way that it does not affect the browser.
This is a quick demonstration of this system in the form in which you can use it as an end user or developer. Let's look at some more examples. For example, how the Native Client will work, or why we need just this, and not an alternative design.
Therefore, if your goal is to isolate your own code, there are several alternatives with which you can do this. In fact, people have had problems with using inherited code and other languages ​​before the Native Client appeared. They solved them in a variety of ways that may not have been as safe and convenient as the Native Client , but provided the same isolation options.
So what should you do if you really want to run the machine code in a browser? One option is to trust the developer. Perhaps the variant of this approach is that you are asking the user whether he wants to run some code fragment in his browser or not.
So, everybody understands what this plan is, right? For example, instead of this whole strategy of compiling the Native Client, I could just create a C program, run it in a browser, and he would ask me if I want to launch this site or not? And if I click "yes", accidentally "nakosyach" in the memory of the browser, it will fail. So it is possible, right? This, of course, solves all these problems, but what's wrong with that?
I think the bad thing is that this solution is not safe. This is one of the ways to “get around” this system and many other systems.
Microsoft had a system called ActiveX , which basically implemented this plan. You could send binary files in IE , a browser on your computer, and until they come back with a certificate from a particular developer, signed by, say, Microsoft or someone else, the browser will not run your code. Do you think this is a useful plan?
Audience: This is a question of trust!
Professor: yes it is. You really need to trust a little that the developer will only sign those “binaries” that will not do anything wrong. But it’s often impossible to find out if it’s a bad thing or not, so they simply write C code and blindly sign it without doing a huge amount of work. In this case, you may well get some problems in the future.
Likewise, the decision to ask the user if he really wants to launch a thing does not guarantee security at all. Even if the user wants to be careful, it is not really clear how he should decide? Suppose I really want to understand, can I let this program work? I am told that everything is fine, maybe it was created by reputable Google.com or Microsoft.com developers. However, this is the executable file foo.exe and I absolutely do not know what is inside it. Even if I disassemble his code, it will be very difficult to say whether he is going to do something bad or not. Therefore, it is really difficult for the user to decide whether the code launch will be safe for the system.
Thus, the Native Client can act as a mechanism by which users can gain some confidence in whether they should say “yes” or “no” to a program.
So in practice, I think, there should be an option that was offered by our guest lecturer Paul Yang last week. He advised running the “ play extension ” plugin, or “play the extension” in the Chrome browser . That is, it turns out that before running any extension, including the Native Client , you need to click on this thing. In some ways, this is the same as asking the user. But in this case, even if the user decides to answer “yes”, the system will still be safe, because the Native Client will be involved in the work. In this sense, we have a double security mechanism: first ask the user, and then, with a positive answer, start the sandbox client, which will not allow the browser to crash.
Thus, another approach that should be applied is to use a sandbox implemented by means of an OS or hardware, or to isolate processes. This is what we considered in the last 2 lectures.
Perhaps you would use Unix isolation mechanisms. If you had something more complicated, you would use FreeBSD or Capsicum . It is great for isolating some piece of code in the sandbox, because you can limit its capabilities. Linux has a similar mechanism called Seccomp , which we briefly touched on in the last lecture, it also allows you to do such things.
Thus, there is already a mechanism for writing code in isolation on your machine. Why are these guys against using this existing solution? It seems that they are “reinventing the wheel” for some reason. So what happens?
Audience: maybe they want to minimize mistakes?
Professor: Yes, in a sense, they do not trust the operating system. Perhaps they are actually worried about OS errors. It is likely that the FreeBSD kernel or the Linux kernel contains quite a lot of C code that they don’t want or cannot verify for correctness, even if they wanted to. And in Capsicum or Seccomp, the work is performed on the basis of the isolation plan, so it is enough that there is only a small correct part of the code in the kernel for the sandbox to maintain and apply the isolation.
Audience: since you get far more ways to use browsers, you will have to deal with different operating systems, such as iOS and Android, and access ...
Professor: yes, in fact, another interesting consideration is that usually many operating systems have errors. And in fact, different operating systems are incompatible with each other in some way. This means that each OS has its own mechanism, as shown here: Unix has Capsicum , Linux has Seccomp , but these are just Unix variations. Mac OS has Seatbelt , Windows has something else, and the list goes on.
So in the end, every platform you work with has its own isolation mechanism. And the fact that they are not really worried about them too much is that they will have to write different code for Mac , Windows and Linux . But to a large extent this affects how you have to write these things to work inside the sandbox. Because in the Native Client you actually write a piece of code that runs the same way as the “native” OS code, in the same way that Apple code, Windows code or Linux system code is executed.
And if you use these isolation mechanisms, they actually impose various restrictions on the program placed in the sandbox. Therefore, you have to write one program that will be used to run inside the Linux sandbox, another program to run inside the Windows sandbox, and so on.
This is actually unacceptable for them. They do not want to deal with problems of this kind. What other thoughts do you have?
Audience: presumably system performance. Because if you use Capsicum , you need to take care of sufficient resources to ensure the work of the processes inside the sandbox. Here they may face the same problem.
Professor: yes, that's true. The software failure isolation plan is actually very resource-intensive, which at the OS level can cause a lack of resources to support the sandbox. It turns out that in their own Native Client, they actually use both their sandbox and OS sandbox for additional security. Thus, in fact, they do not win in the performance of their implementation, although they probably could.
Audience: maybe they want to control everything. Because they can control what is happening in the browser, but if they sent it to the OS on the client's computer, they do not know what could happen there.
Professor: we can say that yes, the OS may have errors or not well cope with the "sandbox". Or the interface is slightly different, so you don’t know what the operating system is going to reveal.
Audience: this will not prevent the code from doing some bad things. There are many such things that the code does, for example, you want to perform static analysis, but looping the code does not allow the program to act.
Professor: in fact, it is very difficult to determine whether an infinitely looped process takes place or not, but in principle, this approach allows us to catch some code problems. I think that one really interesting example, about which I did not know until I read their article, shows that these guys are worried about hardware errors, and not just about OS vulnerabilities, which the launched code can use. For example, the processor itself has some instructions, because of which it can “hang” or restart the computer. In principle, your hardware should not have such an error, because the operating system relies on the fact that the hardware will in any case help it reach the kernel to take care of eliminating the consequences of a user error.
But it turns out that the processors are so complex that they have errors, and these guys say they have found evidence. If there are some complex instructions that the processor did not expect to receive, it will stop instead of processing the core of the system. This is bad. I think it's not disastrous if I just run a few useful things on my laptop, but much worse if the computer freezes when I visit some web pages.
Thus, they wanted to create a higher level of protection for the Native Client modules than the one that provides isolation at the OS level, even free of hardware errors. So about security, they behave like paranoids, including the problem of hardware security.
Let's now see how the Native Client actually isolates processes in the sandbox. Thus, the Native Client uses a different approach, which can be called "isolating software failures."
The plan is not to rely on the operating system or hardware to check things while the program is running, but to rely on their reviewing the instructions in advance and deciding that they can be completed safely. Thus, it is actually enough to look at the binary file to check all possible instructions and see if they will be safe or unsafe. Once you have decided that everything will be safe, you can simply start the process because you know that it consists of safe things and there will be no failures.
So what they are going to do is to watch almost all the instructions in binary code that is sent to the browser, and decide whether specific instructions will be safe or not.
3 months for free if you pay for new Dell R630 for half a year - 2 x Intel Deca-Core Xeon E5-2630 v4 / 128GB DDR4 / 4x1TB HDD or 2x240GB SSD / 1Gbps 10 TB - from $ 99.33 a month , only until the end of August, order can be here .