By Jake Edge
August 19, 2009
Creating a sandbox—a safe area in which to run untrusted
code—is a difficult problem. The successful sandbox implementations
tend to come with completely new languages (e.g. Java) that are
specifically designed to support that functionality. Trying to sandbox C
code is a much more difficult task, but one that the Google Chrome web browser team has
been working on.
The basic idea is to restrict the WebKit-based renderer—along with
the various image and other format libraries that are linked to
it—so that browser-based vulnerabilities are unable to affect the
system as a whole. A successful sandbox for the browser would eliminate
a whole class of problems that plague Firefox and other browsers that
require
frequent, critical security updates. Essentially, the browser would protect
users from bugs in the rendering of maliciously-crafted web pages, so that
they could not lead to system or user data compromise.
The Chrome browser, and its free software counterpart, Chromium, is designed around
the idea of separate processes for each tab, both for robustness and
security. A misbehaving web page can only affect the process controlling
that particular tab, so it won't bring the entire browser down if it causes
the process to crash. In addition, these processes are considered to be
"untrusted", in
that they could have been compromised by some web page exploiting a bug in
the renderer. The sandbox scheme works by severely restricting the actions
that
untrusted processes can take directly.
At some level, Linux already has a boundary that isolates programs from the
underlying system: system calls. A program that does no system calls
should not be able to affect anything else, at least permanently. But it
is a trivial program indeed that does not need to call on some system
services. A largely unknown kernel feature, seccomp, allows processes to
call a very small subset of system calls—just read(),
write(), sigreturn(), and exit()—aborting
a process that attempts to call any other. That is the starting point for
the Chromium sandbox.
But, there are other system calls that the browser might need to make. For
one thing, memory allocation might require the brk() system call.
Also, the renderer needs to be able to share memory with the X server for
drawing. And so on. Any additional system calls, beyond the four that
seccomp allows, have to be handled differently.
A proposed change to seccomp
that would allow finer-grained control over which system calls were allowed
didn't get very far. In any case, that wasn't a near-term solution, so
Markus Gutschke of the Chrome team went in another direction. By splitting
the renderer process into trusted and untrusted threads, some system
calls could be allowed for the untrusted thread by making the equivalent of
a remote procedure call
(RPC) to the trusted thread. The trusted thread could then verify that
the system call, and its arguments, were reasonable and, if so, perform the
requested action.
Chrome team member Adam Langley describes it this way:
So that's what we do: each untrusted thread has a trusted helper thread
running in the same process. This certainly presents a fairly hostile
environment for the trusted code to run in. For one, it can only trust its
CPU registers - all memory must be assumed to be hostile. Since C code will
spill to the stack when needed and may pass arguments on the stack, all the
code for the trusted thread has to [be] carefully written in assembly.
The trusted thread can receive requests to make system calls from the
untrusted thread over a socket pair, validate the system call number and
perform them on its behalf. We can stop the untrusted thread from breaking
out by only using CPU registers and by refusing to let the untrusted code
manipulate the VM in unsafe ways with mmap, mprotect etc.
There are still problems with that approach, however. For one thing, the
renderer code is large, with many different system calls scattered
throughout. Turning each of those into an RPC is possible, but then
would have to
be maintained by the Chromium developers going forward. The upstream
projects (WebKit, et. al.) would
not be terribly interested in those changes, so each new revision from
upstream would need to be patched and then checked for new system calls.
Another approach might be to use LD_PRELOAD trickery to intercept
the calls in glibc. That has its own set of problems as Langley points
out: "we could try and intercept at dynamic linking time, assuming
that all the system calls are via glibc. Even if that were true, glibc's
functions make system calls directly, so we would have to patch at the
level of functions like printf rather than write."
So, a method of finding and patching the system calls at runtime was
devised. It uses a disassembler on the executable code, finds each system
call and turns it into an RPC to the trusted thread. Correctly parsing x86
machine code is notoriously difficult, but it doesn't have to be perfect.
Because the untrusted thread runs in seccomp mode, any system call that is
missed will not lead to a security breach, as the kernel will abort the
thread if it attempts any but the trusted four system calls. As Langley
puts it:
But we don't need a perfect disassembler so long as it works in practice
for the code that we have. It turns out that a simple disassembler does the
job perfectly well, with only a very few corner cases.
The last piece of the puzzle is handling time-of-check-to-time-of-use race
conditions. System call arguments that are passed in memory, via
pointers or for system calls with too many arguments to fit in registers,
can be changed by the, presumably subverted, untrusted
thread between the time they are checked for validity and when they are used.
To handle that, a trusted process, which is shared between all of the
renderers, is created to check system calls that cannot be verified within
the address space of the untrusted renderer.
The trusted process shares a few pages of memory with each trusted thread,
which are read-only to the trusted thread, and read-write for the trusted
process. System calls that cannot be handled by the trusted thread, either
because some of the arguments live in memory, or because the verification
process is too complex to be reasonably done in assembly code, are handed off to
the trusted process. The arguments are copied by the trusted process into
its address space, so they are immune to changes from the untrusted code.
While the current implementation is for x86 and x86-64—though there are
still a few issues to be worked out with the V8 Javascript engine on
x86-64—there is a clear path for other architectures. Adapting or writing a
disassembler and writing the assembly language trusted thread are the two
pieces needed to support each additional architecture. According to
Langley:
The former is probably
easier on many other architectures because they are likely to be more
RISC like. The latter takes some work, but it's a coding problem only
at this point.
There are some potential pitfalls in this sandbox mechanism. Bugs in the
implementation of the trusted pieces—either coding errors or mistakes
made in determining which system calls and arguments are "safe"—could
certainly lead to problems. Currently, deciding which calls to allow is
done on an ad hoc basis, by running the renderer, seeing which calls
it makes, and deciding which are reasonable. The outcome of those
decisions are then codified in syscall_table.c.
One additional, important area that is not covered by the sandbox are
plugins like Flash. Restricting what plugins can do does not fit well with
what users expect, which makes plugins a major vector for attack. Langley said
that the plugin support on Linux is relatively new, but "our experience
on Windows is that, in order for Flash to do all the things that
various sites expect it to be able to do, the sandbox has to be so
full of holes that it's rather useless". He is currently looking at
SELinux as a way to potentially restrict plugins, but, for now, they are
wide open.
This is a rather—some would say overly—complex scheme. It is
still in the experimental stage, so changes are likely, but it does show
one way to protect browser users from bugs in the HTML renderer that might
lead to system or data compromise. It certainly doesn't solve all of the
web's security problems, but could, over time, largely eliminate a whole
class of attacks. It is definitely a project worth keeping an eye on.
[ Many thanks to Adam Langley, whose document was used as a basis for this
article, and who patiently answered questions from the author. ]
Comments (31 posted)
Brief items
Tavis Ormandy has disclosed a new, easily-exploited NULL pointer
vulnerability in the Linux kernel; this one comes from the networking code
when any of a number of relatively obscure protocols are used.
A
fix has been merged into the mainline, but there's likely to be a lot
of exploitable kernels out there.
Full Story (comments: 13)
New vulnerabilities
cdf: buffer overflows
| Package(s): | cdf |
CVE #(s): | CVE-2009-2850
|
| Created: | August 19, 2009 |
Updated: | August 19, 2009 |
| Description: |
Versions of the cdf (common data format) library prior to 3.3.0 suffer from a number of heap-based buffer overflows which could be exploited (by a malicious CDF file) to execute arbitrary code. |
| Alerts: |
|
Comments (none posted)
Compress::Raw::Bzip2: buffer overflow
| Package(s): | Compress::Raw::Bzip2 |
CVE #(s): | CVE-2009-1884
|
| Created: | August 19, 2009 |
Updated: | August 24, 2009 |
| Description: |
The Perl Compress::Raw::Bzip2 library (prior to version 2.020) suffers from a buffer overflow which could possibly be exploited to execute arbitrary code. |
| Alerts: |
|
Comments (none posted)
curl: null prefix vulnerability
| Package(s): | curl wget |
CVE #(s): | CVE-2009-2417
CVE-2009-2408
|
| Created: | August 14, 2009 |
Updated: | June 24, 2011 |
| Description: |
From the Red Hat alert:
Scott Cantor reported that cURL is affected by the previously published
"null prefix attack", caused by incorrect handling of NULL characters in
X.509 certificates. If an attacker is able to get a carefully-crafted
certificate signed by a trusted Certificate Authority, the attacker could
use the certificate during a man-in-the-middle attack and potentially
confuse cURL into accepting it by mistake.
The wget tool also suffers from the same vulnerability. |
| Alerts: |
|
Comments (none posted)
dillo: integer overflow
| Package(s): | dillo |
CVE #(s): | CVE-2009-2294
|
| Created: | August 19, 2009 |
Updated: | August 19, 2009 |
| Description: |
Dillo's PNG-handling code contains an integer overflow vulnerability; version 2.1.1 has the fix. |
| Alerts: |
|
Comments (none posted)
dokuwiki: input sanitization error
| Package(s): | dokuwiki |
CVE #(s): | CVE-2009-1960
|
| Created: | August 19, 2009 |
Updated: | August 19, 2009 |
| Description: |
Dokuwiki (prior to version 2009-02-14b) suffers from an input sanitization error which could enable information disclosure or code execution exploits. |
| Alerts: |
|
Comments (none posted)
kernel: privilege escalation
| Package(s): | kernel |
CVE #(s): | CVE-2009-2692
|
| Created: | August 18, 2009 |
Updated: | October 5, 2009 |
| Description: |
From the Mandriva advisory: The Linux kernel 2.6.0 through 2.6.30.4, and 2.4.4 through 2.4.37.4, does not initialize all function pointers for socket operations in proto_ops structures, which allows local users to trigger a NULL pointer dereference and gain privileges by using mmap to map page zero,
placing arbitrary code on this page, and then invoking an unavailable
operation, as demonstrated by the sendpage operation on a PF_PPPOX
socket. |
| Alerts: |
|
Comments (none posted)
pidgin: remote code execution
| Package(s): | pidgin |
CVE #(s): | CVE-2009-2694
|
| Created: | August 19, 2009 |
Updated: | December 7, 2009 |
| Description: |
A flaw in the Pidgin MSN protocol handler can enable the execution of arbitrary code from a malicious MSN message. |
| Alerts: |
|
Comments (none posted)
thunderbird: multiple vulnerabilities
Comments (none posted)
viewvc: multiple vulnerabilities
| Package(s): | viewvc |
CVE #(s): | |
| Created: | August 13, 2009 |
Updated: | August 19, 2009 |
| Description: |
viewvc has multiple vulnerabilities. From the Fedora alert:
- security fix: validate the 'view' parameter to avoid XSS attack
- security fix: avoid printing illegal parameter names and values |
| Alerts: |
|
Comments (none posted)
zope: multiple vulnerabilities
| Package(s): | zope2.10/zope2.9 |
CVE #(s): | CVE-2009-0668
CVE-2009-0669
|
| Created: | August 19, 2009 |
Updated: | May 11, 2011 |
| Description: |
From the Debian advisory:
Due to a programming error an authorization method in the StorageServer
component of ZEO was not used as an internal method. This allows a
malicious client to bypass authentication when connecting to a ZEO server
by simply calling this authorization method (CVE-2009-0668).
The ZEO server doesn't restrict the callables when unpickling data received
from a malicious client which can be used by an attacker to execute
arbitrary python code on the server by sending certain exception pickles.
This also allows an attacker to import any importable module as ZEO is
importing the module containing a callable specified in a pickle to test
for a certain flag (CVE-2009-0668).
The update also limits the number of new object ids a client can request
to 100 as it would be possible to consume huge amounts of resources by
requesting a big batch of new object ids. No CVE id has been assigned to
this.
|
| Alerts: |
|
Comments (none posted)
Page editor: Jake Edge
Next page: Kernel development>>