[cap-talk] Caps-as-data in Native Client

Mark Seaborn mrs at mythic-beasts.com
Thu May 27 12:03:44 PDT 2010


Native Client currently exposes a caps-as-data interface in the form
of "socket addresses".  I'd like to get some feedback about whether
this is a good thing or not.  It was originally introduced for
implementation-specific reasons, and may need to be removed for
implementation-specific reasons.  It might be useful in its own right,
but it might also be dangerous.

A socket address is one half of a pair of endpoints that are created
with NaCl's imc_makeboundsock() syscall [1]:

  imc_makeboundsock() -> (socket_address, bound_socket)

The holder of socket_address can use it to initiate connections to
bound_socket.  In this way, NaCl socket addresses are similar to Unix
socket addresses such as <ip_address, port> pairs (for TCP sockets) or
pathnames (for Unix domain sockets).  And in fact, on Unix, NaCl
socket addresses are implemented using Unix domain sockets.  The
difference is that NaCl's socket addresses are usually wrapped as a
file descriptor.

So, "socket address" can mean one of three things in NaCl:

 * a string of data, chosen randomly by imc_makeboundsock();
 * a NaCl descriptor that wraps this randomly-chosen string, that
   imc_makeboundsock() returns;
 * a Javascript object that wraps the NaCl descriptor (implemented by
   the NaCl browser plugin).  This wrapper is created if a NaCl
   descriptor is passed via IPC to Javascript.

Socket address descriptors are mostly opaque:  NaCl itself does not
provide a way to extract the string from the descriptor, nor create a
descriptor from a string.

However, the browser plugin *does* provide methods for doing both of
those things [2]:

 * desc.toString() returns the data string
   (As an aside, I suspect it's bad to use toString() as the method
   for doing this if it's the method that Javascript invokes
   implicitly in various contexts.)
 * plugin.__socketAddressFactory(data) creates a descriptor given a data string.

The original reason for the NaCl plugin to expose this functionality
to Javascript is somewhat odd:  it was apparently to provide a way for
Javascript to connect a NaCl process up to the O3D plugin.  (The NaCl
plugin and O3D plugins were separate plugins, and although they live
in the same process when used in the context of Firefox, it was hard
to get the two connected to each other, and NPAPI doesn't provide a
way for one to read the internals of a Javascript object implemented
by the other.)

This original reason has gone, and now the fact that these NaCl
sockets are implemented in terms of connect() and bind() on Unix
domain sockets is causing problems when it comes to running NaCl
inside an outer sandbox.  In the Mac OS X sandbox and the Linux
seccomp sandbox, we don't want to have to allow connect() and bind().

This is not a big problem, because imc_makeboundsock() (and its
sibling syscalls, imc_connect() and imc_accept()) can be reimplemented
in terms of socketpair() and message-passing instead of connect() and
bind()/accept().  This means the Javascript methods for wrapping and
unwrapping socket address strings will have to go.

My initial reaction to __socketAddressFactory()/toString() was that
they are a bad idea, or at least that they shouldn't have been
introduced for the reason that they were, so it would be good to
remove them.  If NaCl can support encapsulated object-capabilities, we
shouldn't relax this to provide password capabilities - and thus
encourage their use - unless we have a good reason.

However, having thought about this more, there could be some good use cases.

For example, suppose you want to grant a web app access to local
storage, implemented outside of the browser.  One way to do this is to
implement the local storage as a web service, running as a local HTTP
server.  The web app could be given an unguessable URL, e.g.
http://localhost:1234/storage/CS6LbJik8DpZcrmikdn, and access the
storage using UMP XmlHttpRequests.  (Granting the unguessable URL can
be done using the Web Powerbox [3].)

However, this means that all the traffic has to be tunnelled across
XmlHttpRequests.  The alternative is to pass the web app a NaCl socket
address string, e.g. "CS6LbJik8DpZcrmikdn".  The app turns this into a
descriptor and imc_connect()s to it.  Then communication can happen
via NaCl descriptors: The storage service can send the app file
descriptors, which the app can then use directly to read and write
storage without the overhead of IPC or XmlHttpRequest.  The app can
even mmap() the files.

One potential problem is that socket address strings are just random
tokens, so if you connect to the string "CS6LbJik8DpZcrmikdn", there
is no cryptographic mechanism (such as a public key) to authenticate
who you are talking to.  So, what could go wrong here?

Mark

[1] http://code.google.com/p/nativeclient/wiki/IMCSockets
[2] http://code.google.com/p/nativeclient/wiki/PluginDomObject
[3] http://lists.w3.org/Archives/Public/public-device-apis/2010May/0133.html


More information about the cap-talk mailing list