July 27, 2011
This article was contributed by Nathan Willis
Google released an update to its Native
Client (NaCl) framework in June, which is an open source utility to enable web developers to deploy faster applications by allowing them to run native binary code in a sandboxed environment within the browser. The new release incorporates API changes and updates to the SDK and toolchain, but the technology remains disabled by default in the Chrome browser. NaCl has been listed as "experimental" since its inception, but the company is beginning to shift its message, trying to attract developers to the platform and other browser makers to the framework.
NaCl is essentially a plugin in which "untrusted" native code can be
executed in a secure, sandboxed environment within the browser. Native
code in this context means machine language — compiled binaries,
delivered as self-contained modules. They do not have access to OS
subsystems or toolkits, but only a minimal support library provided by
NaCl. Most other browsers plugins (Java, Flash, etc.) are already native
code, of course, and like them NaCl modules can only interact with the
containing page's contents through JavaScript and a restrictive API. Of
course, the mere mention of Java and Flash raises warning flags about security and performance, to which Google is
doing its best to respond.
The project has been in development since 2008, and originally ran only on 32-bit x86 architectures, although ARM and 64-bit x86 implementations are now under development as well. Google describes the goal of NaCl as enabling developers to leverage existing software components and legacy applications, and to develop more compute-intensive web applications that would run too slowly in JavaScript or HTML5 — all without compromising security.
Shaking it out
The NaCl plugin isolates code in the sandbox by using the memory
segmentation available in processes, thus providing a contiguous, private
address space for each component — currently 256MB in size. It also
attempts to detect insecure code (and refuses to run it), by restricting
each component to a set of "safe" instructions, and enforcing structural
rules to prevent code obfuscation techniques — such as jumping to a
location in the middle of an instruction. Loaded modules are also read-only in memory, to prevent self-modifying code.
In addition to the "inner sandbox" dedicated to isolating native code
modules, NaCl also implements an "outer sandbox" that intercepts any system
calls. Furthermore, code modules are isolated from each other. They can
only communicate by calling NaCl's inter-module communication (IMC)
mechanism. IMC is a bi-directional datagram service designed to resemble
Unix domain sockets. IMC is also used to facilitate communication between
modules and the document object model (DOM) object that created them
(e.g. a web page or JavaScript application). The DOM object, of course, can pass messages between native modules or provide them access to shared storage.
NaCl also provides two higher-level mechanisms built on top of IMC: the Simple Remote Procedure Call (SRPC) facility, and an implementation of the traditional Netscape Plugin API (NPAPI). SRPC can be used to access native module routines from other modules or directly from JavaScript, while the NPAPI implementation provides access to the same browser facilities and information open to other browser plugins.
Each NaCl module also runs as its own OS process (although at the moment, the NaCl plugin itself is run in the browser's process). NaCl cannot provide secure, cross-platform exception handling for modules to recover from hardware exceptions. As a result, a module that triggers a hardware exception will be shut down by the OS, but, by running each module in its own process, other modules should be unaffected.
Developing NaCl modules
For application developers, the project is also introducing a native code API named Pepper, which is currently provided in C and C++ form. Pepper evolved out of Google's earlier efforts to expand on NPAPI, and is thus sometimes referred to in NaCl documentation as the Pepper Plugin API (PPAPI).
Pepper includes interfaces for NaCl's messaging systems and the existing NPAPI functionality, but also provides interfaces for image handling, 2D drawing, and audio, plus memory management, timing, threads, strongly typed variables, and managing module instances.
June's 0.4 release of the NaCl SDK includes minor changes to the C interfaces, and introduces a new method for including an NaCl module in an HTML page: by linking to it with the src= attribute inside of an <embed> tag. However, there are more substantial changes in the build system. It has migrated to the Python-based SCons build tool in place of GNU make, Cygwin has been removed from the Windows toolchain, and experimental support for Valgrind on 64-bit Linux has been added.
The toolchain itself is built on top of a customized version of GCC and GNU binutils that implement the constraints of the NaCl sandbox. Thus re-compilation is necessary, even for the "existing software components" and "legacy applications" use cases. The NaCl plugin provides a C library customized from NewLib.
As discussed earlier, the current SDK can build binary modules for x86-32, x86-64, and ARM, and there are mechanisms for web developers to provide all three varieties of their module within an application. Google is intent on expanding the processor support offerings, however, by adapting the build tools to produce a "portable" binary instead of the processor-specific code. Portable NaCl (PNaCl) compiles source to an intermediate LLVM bytecode format, which is then translated at runtime into the relevant machine code.
Google maintains a gallery
of NaCl examples, including a Monte Carlo pi calculator, audio synthesizer, and Conway's game of Life. The NaCl white papers also describe internal efforts to port Quake, Bullet, and an H.264 decoder to NaCl, and claim the performance to be "indistinguishable" from normal executables, although that code has evidently not been released to the public.
The view outside the Googleplex
From a security standpoint, most of the ideas implemented by NaCl are
not new. Rather than using code signing to provide a measure of security
as ActiveX does for its binary modules, NaCl uses a static verifier to
check all modules before they are allowed to run, and terminates any that
pass that check and still manage to make an unsafe system call. The
fault-isolation methods used by the code verifier are also well-known. On
the development side, the modified GCC and binutils act as a "trusted"
compiler, in theory ensuring that no unsafe code gets executed in the first
place. Code that doesn't conform to the structural and alignment
requirements that the toolchain emits will be rejected.
Reaction from other browser vendors has been decidedly negative, however. Although NaCl is marketed as an open source project open to any browser developer, both Mozilla and Opera have said they have no interest in the technology, and view it as conflicting with the goal of promoting open standards like HTML5 as the unified, cross-platform target platform for web application developers.
In addition, both browser vendors have focused attention on refuting Google's claim that NaCl enables substantially faster applications in the first place, citing the increased performance of modern JavaScript engines. Last year, Mozilla's Chris Blizzard demonstrated a JavaScript version of Google's own NaCl photo-editing demo running at comparable speeds — although video of the session does not appear to be online, so it is unclear on which version of Firefox the demo ran.
The specific version could make a difference; Mozilla introduced TraceMonkey (a
JavaScript optimizer that compiles certain JavaScript loops down to native
code) with the release of Firefox 3.5 in 2008. Firefox 4.0 then introduced
a second optimizer named JaegerMonkey, further improving
performance. JaegerMonkey is a "just in time" (JIT) compiler that also compiles JavaScript to machine code, and is similar to the optimizer employed by Chrome. Mozilla claims that Firefox achieves better JavaScript performance through the fail-over combination of TraceMonkey and JaegerMonkey than JIT-only solutions. Its successor IonMonkey is projected to perform better still.
Of course, NaCl lines up with Google's interest in promoting
the ChromeOS platform. If NaCl can squeeze additional performance out
of netbook CPUs with code delivered in the browser, the need for
locally-installed applications is reduced. But that concern may not
line up with increasing the performance of standards-based web
applications that run in every browser. The NaCl project itself is not on a
standardization path, although the FAQ hints at interest in pursuing it
If Google remains unsuccessful at persuading the other browsers to include support for NaCl, it might attempt to build NaCl plugins for the other browsers (which it did in years past, but it's been deprecated due to the limitations of having only the NPAPI interface). But it may have a harder time convincing a significant number of developers to re-engineer NaCl-based applications. As tantalizing as "native speed" sounds from afar, the double sandbox security restrictions, limited execution environment, and current need to develop for three separate processor architectures does not sound as exciting up close. As for PNaCl's promise to eliminate the architecture problem by targeting an intermediate byte-code representation instead — that platform starts to sound more and more like client-side Java. Perhaps it does hold the key for a performance increase, but it is not going to be an easy sales pitch.
(
Log in to post comments)