| Index: src/trusted/plugin/srpc/service_runtime.cc
|
| ===================================================================
|
| --- src/trusted/plugin/srpc/service_runtime.cc (revision 2716)
|
| +++ src/trusted/plugin/srpc/service_runtime.cc (working copy)
|
| @@ -1,412 +0,0 @@
|
| -/*
|
| - * Copyright 2008 The Native Client Authors. All rights reserved.
|
| - * Use of this source code is governed by a BSD-style license that can
|
| - * be found in the LICENSE file.
|
| - */
|
| -
|
| -#include "native_client/src/trusted/plugin/srpc/service_runtime.h"
|
| -
|
| -#include <map>
|
| -#include <vector>
|
| -
|
| -#include "native_client/src/include/nacl_string.h"
|
| -#include "native_client/src/include/nacl_macros.h"
|
| -#include "native_client/src/shared/imc/nacl_imc.h"
|
| -#include "native_client/src/shared/platform/nacl_log.h"
|
| -#include "native_client/src/trusted/desc/nacl_desc_imc.h"
|
| -#include "native_client/src/trusted/desc/nrd_xfer.h"
|
| -#include "native_client/src/trusted/desc/nrd_xfer_effector.h"
|
| -#include "native_client/src/trusted/handle_pass/browser_handle.h"
|
| -#include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
|
| -
|
| -#include "native_client/src/trusted/plugin/npapi/multimedia_socket.h"
|
| -#include "native_client/src/trusted/plugin/srpc/browser_interface.h"
|
| -#include "native_client/src/trusted/plugin/srpc/connected_socket.h"
|
| -#include "native_client/src/trusted/plugin/srpc/plugin.h"
|
| -#include "native_client/src/trusted/plugin/srpc/shared_memory.h"
|
| -#include "native_client/src/trusted/plugin/srpc/socket_address.h"
|
| -#include "native_client/src/trusted/plugin/srpc/srt_socket.h"
|
| -#include "native_client/src/trusted/plugin/srpc/scriptable_handle.h"
|
| -#include "native_client/src/trusted/plugin/srpc/utility.h"
|
| -
|
| -#include "native_client/src/trusted/service_runtime/nacl_error_code.h"
|
| -#include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h"
|
| -
|
| -using std::vector;
|
| -
|
| -namespace plugin {
|
| -
|
| -ServiceRuntime::ServiceRuntime(
|
| - BrowserInterface* browser_interface,
|
| - Plugin* plugin) :
|
| - async_receive_desc(NULL),
|
| - async_send_desc(NULL),
|
| - browser_interface_(browser_interface),
|
| - default_socket_address_(NULL),
|
| - default_socket_(NULL),
|
| - plugin_(plugin),
|
| - runtime_channel_(NULL),
|
| - subprocess_(NULL) {
|
| -}
|
| -
|
| -// shm is consumed (Delete invoked).
|
| -bool ServiceRuntime::InitCommunication(nacl::DescWrapper* shm) {
|
| - // TODO(sehr): this should use the new
|
| - // SelLdrLauncher::OpenSrpcChannels interface, which should be free
|
| - // of resource leaks.
|
| - // Channel5 was opened to communicate with the sel_ldr instance.
|
| - // Get the first IMC message and create a socket address from it.
|
| - nacl::Handle channel5 = subprocess_->channel();
|
| - PLUGIN_PRINTF(("ServiceRuntime(%p): opened %p 0x%p\n",
|
| - static_cast<void*>(this), static_cast<void*>(subprocess_),
|
| - reinterpret_cast<void*>(channel5)));
|
| - // GetSocketAddress implicitly invokes Close(channel5).
|
| - default_socket_address_ = GetSocketAddress(plugin_, channel5);
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "Got service channel descriptor %p\n",
|
| - static_cast<void*>(default_socket_address_)));
|
| -
|
| - if (NULL == default_socket_address_) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::InitCommunication "
|
| - "no valid socket address\n"));
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "service runtime: no valid socket address");
|
| - return false;
|
| - }
|
| - ScriptableHandle* raw_channel;
|
| - // The first connect on the socket address returns the service
|
| - // runtime command channel. This channel is created before the NaCl
|
| - // module runs, and is private to the service runtime. This channel
|
| - // is used for a secure plugin<->service runtime communication path
|
| -
|
| -
|
| - // that can be used to forcibly shut down the sel_ldr.
|
| - PLUGIN_PRINTF((" connecting for SrtSocket\n"));
|
| - PortableHandle* portable_socket_address = default_socket_address_->handle();
|
| - raw_channel = portable_socket_address->Connect();
|
| - if (NULL == raw_channel) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "service runtime Connect failed.\n"));
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "service runtime Connect failed");
|
| - return false;
|
| - }
|
| - PLUGIN_PRINTF((" constructing SrtSocket\n"));
|
| - runtime_channel_ = new(std::nothrow) SrtSocket(raw_channel,
|
| - browser_interface_);
|
| - if (NULL == runtime_channel_) {
|
| - // TODO(sehr): leaking raw_channel.
|
| - return false;
|
| - }
|
| -
|
| - // Set module's origin at the service runtime. NB: we may end up
|
| - // enforcing restrictions for network access to the origin of the
|
| - // module only in the plugin. Here's why:
|
| - //
|
| - // When a plugin using NPAPI invokes NPP_GetURLNotify (on the behalf
|
| - // of a NaCl module), it may provide a relative URL; even if it is
|
| - // not a relative URL, 3xx redirects may change the source domain of
|
| - // the actual web content as a side effect -- the 3xx redirects
|
| - // cause the browser to make new HTTP connections, and the browser
|
| - // does not notify the plugin as this is occurring. However, when
|
| - // the browser invokes NPN_NewStream and then either
|
| - // NPN_StreamAsFile or NPP_WriteReady/NPP_Write to deliver the
|
| - // content, the NPStream object contains the fully-qualified URL of
|
| - // the web content, after redirections (if any). This means that we
|
| - // should parse the FQ-URL at NPN_NewStream or NPN_StreamAsFile,
|
| - // rather than try to canonicalize the URL before passing it to
|
| - // NPP_GetURLNotify, since we won't know the final FQ-URL at that
|
| - // point.
|
| - //
|
| - // This strategy also implies that we might allow any URL, e.g., a
|
| - // tinyurl.com redirecting URL, to be used with NPP_GetURLNotify,
|
| - // and allow the access if the final FQ-URL is the same domain.
|
| - // This has the hazard that we still are doing fetches to other
|
| - // domains (including sending cookies specific to those domains),
|
| - // just not making the results available to the NaCl module; the
|
| - // same thing occurs if IMG SRC tags were scripted.
|
| - //
|
| - // A perhaps more important downside is that this is an easy way for
|
| - // NaCl modules to leak information: the target web server is always
|
| - // contacted, since we don't know if
|
| - // http://evil.org/leak?s3kr1t_inf0 might result in a 3xx redirect
|
| - // to an acceptable origin. If we want to prevent this, we could
|
| - // require that all URLs given to NPP_GetURLNotify are either
|
| - // relative or are absolute with the same origin as the module; this
|
| - // would prevent the scenario where an evil module is hosted (e.g.,
|
| - // in temporary upload directory that's visible, or as a gmail
|
| - // attachment URL) at an innocent server to extract confidential
|
| - // info and send it to third party servers. An explict network ACL
|
| - // a la /robots.txt might be useful to serve as an ingress filter.z
|
| -
|
| - PLUGIN_PRINTF(("invoking set_origin\n"));
|
| - if (!runtime_channel_->SetOrigin(plugin_->nacl_module_origin())) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "set_origin RPC failed.\n"));
|
| - browser_interface_->Alert(plugin()->instance_id(), "Could not set origin");
|
| - // TODO(sehr): leaking raw_channel and runtime_channel_.
|
| - return false;
|
| - }
|
| -
|
| - if (shm != NULL) {
|
| - // This code is executed only if NaCl is running as a built-in plugin
|
| - // in Chrome.
|
| - // We now have an open communication channel to the sel_ldr process,
|
| - // so we can send the nexe bits over
|
| - if (!runtime_channel_->LoadModule(shm->desc())) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start failed to send nexe\n"));
|
| - browser_interface_->Alert(plugin()->instance_id(), "failed to send nexe");
|
| - shm->Delete();
|
| - // TODO(gregoryd): close communication channels
|
| - delete subprocess_;
|
| - subprocess_ = NULL;
|
| - return false;
|
| - }
|
| - /* LoadModule succeeded, proceed normally */
|
| - shm->Delete();
|
| -#if NACL_WINDOWS && !defined(NACL_STANDALONE)
|
| - // Establish the communication for handle passing protocol
|
| - struct NaClDesc* desc = NaClHandlePassBrowserGetSocketAddress();
|
| - if (!runtime_channel_->InitHandlePassing(desc, subprocess_->child())) {
|
| - delete subprocess_;
|
| - subprocess_ = NULL;
|
| - return false;
|
| - }
|
| -#endif
|
| - }
|
| -
|
| - // start the module. otherwise we cannot connect for multimedia
|
| - // subsystem since that is handled by user-level code (not secure!)
|
| - // in libsrpc.
|
| - int load_status;
|
| -
|
| - PLUGIN_PRINTF((" invoking start_module RPC\n"));
|
| - if (!runtime_channel_->StartModule(&load_status)) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "module_start RPC failed.\n"));
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "Could not start nacl module");
|
| -
|
| - // TODO(sehr): leaking raw_channel and runtime_channel_.
|
| - return false;
|
| - }
|
| - PLUGIN_PRINTF((" start_module returned %d\n", load_status));
|
| - if (LOAD_OK != load_status) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "module load status %d",
|
| - load_status));
|
| - nacl::stringstream ss;
|
| - ss << "Loading of module failed with status " << load_status;
|
| - browser_interface_->Alert(plugin()->instance_id(), ss.str());
|
| - // TODO(sehr): leaking raw_channel and runtime_channel_.
|
| - return false;
|
| - }
|
| -
|
| - // The second connect on the socket address is to the untrusted side
|
| - // of sel_ldr.
|
| - default_socket_ = portable_socket_address->Connect();
|
| - if (NULL == default_socket_) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start: "
|
| - "SRPC channel Connect failed.\n"));
|
| - // TODO(sehr): leaking raw_channel and runtime_channel_.
|
| - return false;
|
| - }
|
| - default_socket_->handle()->StartJSObjectProxy(plugin_);
|
| - plugin_->EnableVideo();
|
| - // Create the listener thread and initialize the nacl module.
|
| - if (!plugin_->InitializeModuleMultimedia(default_socket_, this)) {
|
| - // TODO(sehr): leaking raw_channel, runtime_channel_, and default_socket_.
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool ServiceRuntime::Start(const char* nacl_file) {
|
| - // The arguments we want to pass to the service runtime are
|
| - // "-P 5" sets the default SRPC channel to be over descriptor 5. The 5 needs
|
| - // to match the 5 in the Launcher invocation below.
|
| - // "-X 5" causes the service runtime to create a bound socket and socket
|
| - // address at descriptors 3 and 4. The socket address is transferred as
|
| - // the first IMC message on descriptor 5. This is used when connecting
|
| - // to socket addresses.
|
| - // "-d" (not default) invokes the service runtime in debug mode.
|
| - // const char* kSelLdrArgs[] = { "-P", "5", "-X", "5" };
|
| - const char* kSelLdrArgs[] = { "-P", "5", "-X", "5" };
|
| - // TODO(sehr): remove -P support and default channels.
|
| - const int kSelLdrArgLength = NACL_ARRAY_SIZE(kSelLdrArgs);
|
| - vector<nacl::string> kArgv(kSelLdrArgs, kSelLdrArgs + kSelLdrArgLength);
|
| - vector<nacl::string> kEmpty;
|
| -
|
| - PLUGIN_PRINTF(("ServiceRuntime::ServiceRuntime"
|
| - "(%p, %p, %s)\n",
|
| - static_cast<void*>(this),
|
| - static_cast<void*>(plugin()),
|
| - nacl_file));
|
| -
|
| - subprocess_ = new(std::nothrow) nacl::SelLdrLauncher();
|
| - if (NULL == subprocess_) {
|
| - PLUGIN_PRINTF(("ServiceRuntime: Could not create SelLdrLauncher"));
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "Could not create SelLdrLauncher");
|
| - return false;
|
| - }
|
| - subprocess_->Init(nacl_file, 5, kArgv, kEmpty);
|
| -
|
| - nacl::Handle receive_handle = subprocess_->ExportImcFD(6);
|
| - if (receive_handle == nacl::kInvalidHandle) {
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "Failed to create async receive handle");
|
| - return false;
|
| - }
|
| - async_receive_desc = plugin()->wrapper_factory()->MakeImcSock(receive_handle);
|
| -
|
| - nacl::Handle send_handle = subprocess_->ExportImcFD(7);
|
| - if (send_handle == nacl::kInvalidHandle) {
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "Failed to create async send handle");
|
| - return false;
|
| - }
|
| - async_send_desc = plugin()->wrapper_factory()->MakeImcSock(send_handle);
|
| -
|
| - if (!subprocess_->Launch()) {
|
| - PLUGIN_PRINTF(("ServiceRuntime: Could not start SelLdrLauncher"));
|
| - browser_interface_->Alert(plugin()->instance_id(),
|
| - "Could not start SelLdrLauncher");
|
| - delete subprocess_;
|
| - subprocess_ = NULL;
|
| - return false;
|
| - }
|
| -
|
| - // TODO(gregoryd) - this should deal with buffer and size correctly
|
| - // - do we need to send the load command from here?
|
| - if (!InitCommunication(NULL)) {
|
| - return false;
|
| - }
|
| -
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start was successful\n"));
|
| - return true;
|
| -}
|
| -
|
| -// Chromium version.
|
| -bool ServiceRuntime::Start(const char* url, nacl::DescWrapper* shm) {
|
| - subprocess_ = new(std::nothrow) nacl::SelLdrLauncher();
|
| - if (NULL == subprocess_) {
|
| - return false;
|
| - }
|
| - if (!subprocess_->Start(url, 5)) {
|
| - delete subprocess_;
|
| - subprocess_ = NULL;
|
| - return false;
|
| - }
|
| -
|
| - if (!InitCommunication(shm)) {
|
| - return false;
|
| - }
|
| -
|
| - PLUGIN_PRINTF(("ServiceRuntime::Start was successful\n"));
|
| - return true;
|
| -}
|
| -
|
| -bool ServiceRuntime::Kill() {
|
| - return subprocess_->KillChild();
|
| -}
|
| -
|
| -bool ServiceRuntime::Log(int severity, nacl::string msg) {
|
| - return runtime_channel_->Log(severity, msg);
|
| -}
|
| -
|
| -void ServiceRuntime::Shutdown() {
|
| - if (subprocess_ != NULL) {
|
| - Kill();
|
| - }
|
| - // This waits for the upcall thread to exit so it must come after we
|
| - // terminate the subprocess.
|
| - plugin_->ShutdownMultimedia();
|
| -
|
| - // Note that this does waitpid() to get rid of any zombie subprocess.
|
| - delete subprocess_;
|
| - subprocess_ = NULL;
|
| -
|
| - delete runtime_channel_;
|
| - runtime_channel_ = NULL;
|
| -}
|
| -
|
| -ServiceRuntime::~ServiceRuntime() {
|
| - PLUGIN_PRINTF(("ServiceRuntime::~ServiceRuntime(%p)\n",
|
| - static_cast<void*>(this)));
|
| -
|
| - // We do this just in case Terminate() was not called.
|
| - delete subprocess_;
|
| - delete runtime_channel_;
|
| -
|
| - if (async_receive_desc != NULL) {
|
| - async_receive_desc->Delete();
|
| - }
|
| - if (async_send_desc != NULL) {
|
| - async_send_desc->Delete();
|
| - }
|
| -}
|
| -
|
| -ScriptableHandle* ServiceRuntime::default_socket_address() const {
|
| - PLUGIN_PRINTF(("ServiceRuntime::default_socket_address(%p) = %p\n",
|
| - static_cast<void*>(const_cast<ServiceRuntime*>(this)),
|
| - static_cast<void*>(const_cast<ScriptableHandle*>(
|
| - default_socket_address_))));
|
| -
|
| - return default_socket_address_;
|
| -}
|
| -
|
| -ScriptableHandle* ServiceRuntime::default_socket() const {
|
| - PLUGIN_PRINTF(("ServiceRuntime::default_socket(%p) = %p\n",
|
| - static_cast<void*>(const_cast<ServiceRuntime*>(this)),
|
| - static_cast<void*>(const_cast<ScriptableHandle*>(
|
| - default_socket_))));
|
| -
|
| - return default_socket_;
|
| -}
|
| -
|
| -ScriptableHandle* ServiceRuntime::GetSocketAddress(
|
| - Plugin* plugin,
|
| - nacl::Handle channel) {
|
| - nacl::DescWrapper::MsgHeader header;
|
| - nacl::DescWrapper::MsgIoVec iovec[1];
|
| - unsigned char bytes[NACL_ABI_IMC_USER_BYTES_MAX];
|
| - nacl::DescWrapper* descs[NACL_ABI_IMC_USER_DESC_MAX];
|
| -
|
| - PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress(%p, %p)\n",
|
| - static_cast<void*>(plugin),
|
| - reinterpret_cast<void*>(channel)));
|
| -
|
| - ScriptableHandle* retval = NULL;
|
| - nacl::DescWrapper* imc_desc = plugin->wrapper_factory()->MakeImcSock(channel);
|
| - // Set up to receive a message.
|
| - iovec[0].base = bytes;
|
| - iovec[0].length = NACL_ABI_IMC_USER_BYTES_MAX;
|
| - header.iov = iovec;
|
| - header.iov_length = NACL_ARRAY_SIZE(iovec);
|
| - header.ndescv = descs;
|
| - header.ndescv_length = NACL_ARRAY_SIZE(descs);
|
| - header.flags = 0;
|
| - // Receive the message.
|
| - ssize_t ret = imc_desc->RecvMsg(&header, 0);
|
| - // Check that there was exactly one descriptor passed.
|
| - if (0 > ret || 1 != header.ndescv_length) {
|
| - PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress: "
|
| - "message receive failed %" NACL_PRIdS " %" NACL_PRIdNACL_SIZE
|
| - " %" NACL_PRIdNACL_SIZE "\n", ret,
|
| - header.ndescv_length,
|
| - header.iov_length));
|
| - goto cleanup;
|
| - }
|
| - PLUGIN_PRINTF(("ServiceRuntime::GetSocketAddress: "
|
| - "-X result descriptor (DescWrapper*) = %p\n",
|
| - static_cast<void*>(descs[0])));
|
| - retval = browser_interface_->NewScriptableHandle(
|
| - SocketAddress::New(plugin, descs[0]));
|
| - cleanup:
|
| - imc_desc->Delete();
|
| - PLUGIN_PRINTF((" returning %p\n", static_cast<void*>(retval)));
|
| - return retval;
|
| -}
|
| -
|
| -} // namespace plugin
|
|
|