Monday, October 19, 2009

Chromium and Linux sandboxing

It was great to talk to so many people about Chromium security at HITB Malaysia. I was quite amused to be at a security conference and have a lot of conversations like:

Me: What browser do you use?
Other: Google Chrome.
Me: Why is that?
Other: Oh, it's so much faster.
Me: Oh, you saw that awesome JSNES, huh? (http://benfirshman.com/projects/jsnes/)

It's a sobering reminder that users -- and even security experts -- are often making decisions on things like speed and stability. It was similar with vsftpd. I set out to build the most secure FTP server, but usage took off unexpectedly because of the speed and scalability.

Julien talked about his clever Linux sandboxing trick that is used in the Chromium Linux port. One component of the sandbox is an empty chroot() jail, but setting up such a jail is a pain on many levels. The problems and solutions are as follows:
  • chroot() needs root privilege. Therefore, a tiny setuid wrapper binary has been created to execute sandboxed renderer processes. Some people will incorrectly bleat and moan about any new setuid binary, but the irony is that is it required to make your browser more secure. Also, a setuid binary can be made small and careful. It will only execute a specific trusted binary (the Chromium renderer) inside an empty jail.

  • exec()ing something from inside an empty jail is hard, because your view of the filesystem is empty. You could include copies of the needed dynamic libraries or a static executable but both of these are a maintenance and packaging nightmare. This is where Julien's clever tweak comes in. By using the clone() flag CLONE_FS, and sharing the FS structure between a trusted / privileged thread and the exec()ed renderer, the trusted thread can call chroot() and have it affect the unprivileged, untrusted renderer process post-exec. Neat, huh?

  • Other tricks such as CLONE_NEWPID and CLONE_NEWNET are used or will be used to prevent sending of signals from a compromised renderer, and network access.

Finally, it is worth noting that sandboxing vs. risks on the web are widely misunderstood. The current Chromium sandbox mitigates Critical risk bugs to High risk bugs. This may be enhanced in the future. Since any bugs within the sandbox are still High risk, I of course take them very seriously and fix them as a priority. But, that lowering of a certain percentage of your bugs away from Critical risk is really key. The vast majority of web pwnage out there is enabled by Critical risk bugs (i.e. full compromise of user account => ability to install malware), so mitigating any of these down to High is a huge win. It's easy to get excited about any security bug, we as an industry really need to get more practical and concentrate on the ones actually causing damage.

Attacking this point from another angle: any complicated software will inevitably have bugs, and a certain subset of bugs are security bugs. Note that any web browser is certainly a complicated piece of software :) Therefore, any web browser is always going to be having security bugs. And indeed, IE, Opera, Firefox, Safari and Chrome are issuing regular security updates. For some reason, the media reports on each and every patch as if it is a surprising or relevant event. The real question, of course, is what you do in the face of the above realization. The Chromium story is two powerful mitigations: sandboxing to reduce severity away from Critical, and a very fast and agile update system to close any window of risk.

1 comment:

Sang said...

Hello. I'm planning to make a sandbox program.
This program monitors arbitrary code, and print warning when child process does a forbidden action like file i/o.
I'm trying to make this program using ptrace and got stuck, because I cannot tell whether it's printf action or file output action.
I want to implement a funtion like http://codepad.org. It monitors user program's system call perfectly, even if it's a interpreter language.
Could you help me?.
I'm looking for an answer for months. Thanks.