Index: components/nacl/loader/nonsfi/nonsfi_listener.cc |
diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.cc b/components/nacl/loader/nonsfi/nonsfi_listener.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..839772cf5e6173312a3e096a6d1c039ecbdfbf65 |
--- /dev/null |
+++ b/components/nacl/loader/nonsfi/nonsfi_listener.cc |
@@ -0,0 +1,150 @@ |
+// Copyright 2014 The Chromium 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 "components/nacl/loader/nonsfi/nonsfi_listener.h" |
+ |
+#include "base/command_line.h" |
+#include "base/file_descriptor_posix.h" |
+#include "base/logging.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/rand_util.h" |
+#include "components/nacl/common/nacl_messages.h" |
+#include "components/nacl/common/nacl_types.h" |
+#include "components/nacl/loader/nacl_trusted_listener.h" |
+#include "components/nacl/loader/nonsfi/irt_random.h" |
+#include "components/nacl/loader/nonsfi/nonsfi_main.h" |
+#include "ipc/ipc_channel.h" |
+#include "ipc/ipc_channel_handle.h" |
+#include "ipc/ipc_switches.h" |
+#include "ipc/ipc_sync_channel.h" |
+#include "ppapi/nacl_irt/plugin_startup.h" |
+ |
+#if !defined(OS_LINUX) |
+# error "non-SFI mode is supported only on linux." |
+#endif |
+ |
+namespace nacl { |
+namespace nonsfi { |
+ |
+NonSfiListener::NonSfiListener() : io_thread_("NaCl_IOThread"), |
+ shutdown_event_(true, false) { |
+ io_thread_.StartWithOptions( |
+ base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
+} |
+ |
+NonSfiListener::~NonSfiListener() { |
+} |
+ |
+void NonSfiListener::Listen() { |
+ channel_ = IPC::SyncChannel::Create( |
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ switches::kProcessChannelID), |
+ IPC::Channel::MODE_CLIENT, |
+ this, // As a Listener. |
+ io_thread_.message_loop_proxy().get(), |
+ true, // Create pipe now. |
+ &shutdown_event_); |
+ base::MessageLoop::current()->Run(); |
+} |
+ |
+bool NonSfiListener::Send(IPC::Message* msg) { |
+ DCHECK(channel_.get() != NULL); |
+ return channel_->Send(msg); |
+} |
+ |
+bool NonSfiListener::OnMessageReceived(const IPC::Message& msg) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(NonSfiListener, msg) |
+ IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart) |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ return handled; |
+} |
+ |
+void NonSfiListener::OnStart(const nacl::NaClStartParams& params) { |
+ // Random number source initialization. |
+ SetUrandomFd(base::GetUrandomFD()); |
+ |
+ IPC::ChannelHandle browser_handle; |
+ IPC::ChannelHandle ppapi_renderer_handle; |
+ IPC::ChannelHandle manifest_service_handle; |
+ |
+ if (params.enable_ipc_proxy) { |
+ browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
+ ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl"); |
+ manifest_service_handle = |
+ IPC::Channel::GenerateVerifiedChannelID("nacl"); |
+ |
+ // In non-SFI mode, we neither intercept nor rewrite the message using |
+ // NaClIPCAdapter, and the channels are connected between the plugin and |
+ // the hosts directly. So, the IPC::Channel instances will be created in |
+ // the plugin side, because the IPC::Listener needs to live on the |
+ // plugin's main thread. However, on initialization (i.e. before loading |
+ // the plugin binary), the FD needs to be passed to the hosts. So, here |
+ // we create raw FD pairs, and pass the client side FDs to the hosts, |
+ // and the server side FDs to the plugin. |
+ int browser_server_ppapi_fd; |
+ int browser_client_ppapi_fd; |
+ int renderer_server_ppapi_fd; |
+ int renderer_client_ppapi_fd; |
+ int manifest_service_server_fd; |
+ int manifest_service_client_fd; |
+ if (!IPC::SocketPair( |
+ &browser_server_ppapi_fd, &browser_client_ppapi_fd) || |
+ !IPC::SocketPair( |
+ &renderer_server_ppapi_fd, &renderer_client_ppapi_fd) || |
+ !IPC::SocketPair( |
+ &manifest_service_server_fd, &manifest_service_client_fd)) { |
+ LOG(ERROR) << "Failed to create sockets for IPC."; |
+ return; |
+ } |
+ |
+ // Set the plugin IPC channel FDs. |
+ ppapi::SetIPCFileDescriptors(browser_server_ppapi_fd, |
+ renderer_server_ppapi_fd, |
+ manifest_service_server_fd); |
+ ppapi::StartUpPlugin(); |
+ |
+ // Send back to the client side IPC channel FD to the host. |
+ browser_handle.socket = |
+ base::FileDescriptor(browser_client_ppapi_fd, true); |
+ ppapi_renderer_handle.socket = |
+ base::FileDescriptor(renderer_client_ppapi_fd, true); |
+ manifest_service_handle.socket = |
+ base::FileDescriptor(manifest_service_client_fd, true); |
+ } |
+ |
+ // TODO(teravest): Do we plan on using this renderer handle for nexe loading |
+ // for non-SFI? Right now, passing an empty channel handle instead causes |
+ // hangs, so we'll keep it. |
+ trusted_listener_ = new NaClTrustedListener( |
+ IPC::Channel::GenerateVerifiedChannelID("nacl"), |
+ io_thread_.message_loop_proxy().get()); |
+ if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated( |
+ browser_handle, |
+ ppapi_renderer_handle, |
+ trusted_listener_->TakeClientChannelHandle(), |
+ manifest_service_handle))) |
+ LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost."; |
+ |
+ // Ensure that the validation cache key (used as an extra input to the |
+ // validation cache's hashing) isn't exposed accidentally. |
+ CHECK(!params.validation_cache_enabled); |
+ CHECK(params.validation_cache_key.size() == 0); |
+ CHECK(params.version.size() == 0); |
+ // Ensure that a debug stub FD isn't passed through accidentally. |
+ CHECK(!params.enable_debug_stub); |
+ CHECK(params.debug_stub_server_bound_socket.fd == -1); |
+ |
+ CHECK(!params.uses_irt); |
+ CHECK(params.handles.empty()); |
+ |
+ CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit()); |
+ CHECK(params.nexe_token_lo == 0); |
+ CHECK(params.nexe_token_hi == 0); |
+ MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file)); |
+} |
+ |
+} // namespace nonsfi |
+} // namespace nacl |