![](https://csdnimg.cn/release/download_crawler_static/1517642/bg3.jpg)
application might optionally be able to use a (hypothetical)
trusted NaCl service for local storage of images, illustrated
in Figure 2. Because it has access to local disk, the storage
service must be installed as a native browser plugin; it
can’t be implemented as a NaCl module. Suppose the photo
application has been designed to optionally use the stable
storage service; the user interface would check for the stable
storage plugin during initialization. If it detected the storage
service plugin, the user interface would establish an IMC
communications channel to it, and pass a descriptor for the
channel to the image library, enabling the image library and
the storage service to communicate directly via IMC-based
services (SRPC, shared memory, etc.). In this case the NaCl
module will typically be statically linked against a library
that provides a procedural interface for accessing the storage
service, hiding details of the IMC-level communications
such as whether it uses SRPC or whether it uses shared
memory. Note that the storage service must assume that the
image library is untrusted. The service is responsible for
insuring that it only services requests consistent with the
implied contract with the user. For example, it might enforce
a limit on total disk used by the photo application and
might further restrict operations to only reference a particular
directory.
Native Client is ideal for application components requir-
ing pure computation. It is not appropriate for modules
requiring process creation, direct file system access, or
unrestricted access to the network. Trusted facilities such
as storage should generally be implemented outside of
Native Client, encouraging simplicity and robustness of the
individual components and enforcing stricter isolation and
scrutiny of all components. This design choice echoes micro-
kernel operating system design [2], [12], [25].
With this example in mind we will now describe the
design of key NaCl system components in more detail.
2.1. The Inner Sandbox
Native Client is built around an x86-specific intra-process
“inner sandbox.” We believe that the inner sandbox is robust;
regardless, to provide defense in depth [13], [16] we have
also developed a second “outer sandbox” that mediates
system calls at the process boundary. The outer sandbox
is substantially similar to prior structures (systrace [50] and
Janus [24]) and we will not discuss it in detail in this paper.
The inner sandbox uses static analysis to detect security
defects in untrusted x86 code. Previously, such analysis
has been challenging for arbitrary x86 code due to such
practices as self-modifying code and overlapping instruc-
tions. In Native Client we disallow such practices through a
set of alignment and structural rules that, when observed,
insure that the native code module can be disassembled
reliably, such that all reachable instructions are identified
during disassembly. With reliable disassembly as a tool, our
validator can then insure that the executable includes only
the subset of legal instructions, disallowing unsafe machine
instructions.
The inner sandbox further uses x86 segmented memory
to constrain both data and instruction memory references.
Leveraging existing hardware to implement these range
checks greatly simplifies the runtime checks required to con-
strain memory references, in turn reducing the performance
impact of safety mechanisms.
This inner sandbox is used to create a security subdomain
within a native operating system process. With this organiza-
tion we can place a trusted service runtime subsystem within
the same process as the untrusted application module, with
a secure trampoline/springboard mechanism to allow safe
transfer of control from trusted to untrusted code and vice-
versa. Although in some cases a process boundary could
effectively contain memory and system-call side effects, we
believe the inner sandbox can provide better security. We
generally assume that the operating system is not defect
free, such that the process barrier might have defects, and
further that the operating system might deliberately map
resources such as shared libraries into the address space of
all processes, as occurs in Microsoft Windows. In effect our
inner sandbox not only isolates the system from the native
module, but also helps to isolate the native module from the
operating system.
2.2. Runtime Facilities
The sandboxes prevent unwanted side effects, but some
side effects are often necessary to make a native mod-
ule useful. For interprocess communications, Native Client
provides a reliable datagram abstraction, the “Inter-Module
Communications” service or IMC. The IMC allows trusted
and untrusted modules to send/receive datagrams consisting
of untyped byte arrays along with optional “NaCl Resource
Descriptors” to facilitate sharing of files, shared mem-
ory objects, communication channels, etc., across process
boundaries. The IMC can be used by trusted or untrusted
modules, and is the basis for two higher-level abstractions.
The first of these, the Simple Remote Procedure Call (SRPC)
facility, provides convenient syntax for defining and using
subroutines across NaCl module boundaries, including calls
to NaCl code from JavaScript in the browser. The second,
NPAPI, provides a familiar interface to interact with browser
state, including opening URLs and accessing the DOM, that
conforms to existing constraints for content safety. Either of
these mechanisms can be used for general interaction with
conventional browser content, including content modifica-
tions, handling mouse and keyboard activity, and fetching
additional site content; substantially all the resources com-
monly available to JavaScript.
As indicated above, the service runtime is responsible
for providing the container through which NaCl modules
3