the untrusted user code and the trusted service runtime
code. Since every 0 mod 32 address in the second 64KB of
the NaCl user space is a potential computed control flow
target, these are our entry points to a table of system-call
trampolines. One of these entry points is blocked with a
hlt instruction, so that the remaining space may be used
for code that can only be invoked from the service runtime.
This provides space for the springboard return gate.
Invocation of a trampoline transfers control from
untrusted code to trusted code. The trampoline sequence
register and transfer control to trusted service handlers,
reestablishing the conventional flat addressing model
expected by the code in the service runtime. Once outside
the NaCl user address space, it resets other segment registers such as %fs, %gs, and %ss to reestablish the native
code threading environment, fully disabling the inner
sandbox for this thread, and loads the stack register %esp
with the location of a trusted stack for use by the service
runtime. Note that the per-thread trusted stack resides outside the untrusted address space, to protect it from attack
by other threads in the untrusted NaCl module.
Just as trampolines permit crossing from untrusted to
trusted code, the springboard enables crossing in the other
direction. The springboard is used by the trusted runtime:
• To transfer control to an arbitrary untrusted address.
• To start a new POSIX-style thread.
• To start the main thread.
Alignment ensures that the springboard cannot be invoked
directly by untrusted code. The ability to jump to an arbitrary untrusted address is used in returning from a service
call. The return from a trampoline call requires popping
an unused trampoline return address from the top of the
stack, restoring the segment registers, and finally aligning
and jumping to the return address in the NaCl module.
As a point of comparison, we measured the overhead of
a “null” system call. The Linux overhead of 156 ns is slightly
higher than that of the Linux 2. 6 getpid syscall time, on the
same hardware, of 138 ns (implemented via the vsyscall
table and using the sysenter instruction). We note that
the user/kernel transfer has evolved continuously over the
life of the x86 architecture. By comparison, the segment
register operations and far calls used by the NaCl trampoline are somewhat less common, and may have received
less consideration over the history of the x86 architecture.
3. 4. communications
The IMC is the basis of communications into and out of
NaCl modules. The implementation is built around a NaCl
socket, providing a bidirectional, reliable, in-order datagram
service similar to Unix domain sockets.
13 An untrusted NaCl
module receives its first NaCl socket when it is created,
to the NaCl module, and can also share it with other NaCl
module to other services available to it by opening and
sharing NaCl sockets as NaCl descriptors. NaCl descriptors
can also be used to create shared memory regions.
Using NaCl messages, Native Client’s SRPC abstraction
is implemented entirely in untrusted code. SRPC provides
a convenient syntax for declaring procedural interfaces
NaCl modules, supporting a few simple types (e.g. int, float,
char), arrays of simple types, and Na Cl descriptors. Pointers
are not supported. Higher-level data representations can
easily be layered on top of IMC messages or SRPC.
Our NPAPI implementation is also layered on top of the
IMC and supports a subset of the common NPAPI interface.
Specific requirements that shaped the current implementation are the ability to read, modify, and invoke properties
and methods on the script objects in the browser, support for
simple raster graphics, provide the createArray() method
and the ability to open and use a URL like a file descriptor. We
are currently studying some additional refinements to NPAPI
for improved portability, performance and safety.b
3. 5. Developer tools
Building naCl Modules: We have modified the standard
GNU tool chain, using version 4. 2. 2 of the gcc collection
of compilersc and version 2. 18 of binutilsd to generate
NaCl-compliant binaries. We have built a reference binary
from newlibe using the resulting tool chain, rehosted to use
the NaCl trampolines to implement system services
(e.g., read(), brk(), gettimeofday(), imc_sendmsg()).
Native Client supports an insecure “debug” mode that allows
additional file-system interaction not otherwise allowed for
We modified gcc for Native Client by changing the alignment of function entries (-falign-functions) to 32
bytes and by changing the alignment of the targets branches
(-falign-jumps) to 32 bytes. We also changed gcc to use
nacljmp for indirect control transfers, including indirect
calls and all returns. We made more significant changes to
the assembler, to implement Native Client’s block alignment requirements. To implement returns, the assembler
ensures that call instructions always appear in the final bytes
of a 32-byte block. We also modified the assembler to implement indirect control transfer sequences by expanding the
nacljmp pseudo-instruction as a properly aligned consecutive block of bytes. To facilitate testing we added support to
use a longer nacljmp sequence, align the text base, and use
an and and or that uses relocations as masks. This permits
testing applications by running them on the command line,
and has been used to run the entire gcc C/C++ test suite. We
also changed the linker to set the base address of the image
as required by the NaCl loader (128KB today).
Apart from their direct use the tool chain also serves
to document by example how to modify an existing tools
chain to generate NaCl modules. These changes were
achieved with less than 1000 lines total to be patched in
b See https://wiki.mozilla.org/Plugins: PlatformIndependentNPAPI
c See http://gcc.gnu.org
d See http://www.gnu.org/software/binutils/
e See http://sourceware.org/newlib/