diff options
author | hidehiko@chromium.org <hidehiko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 08:54:49 +0000 |
---|---|---|
committer | hidehiko@chromium.org <hidehiko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-08 08:56:18 +0000 |
commit | 8b12bb8af86c39409c215e557074b0e6cbe6212f (patch) | |
tree | 3d3a8f325b4684c529479bd47ce1a73782dcfbcd /components/nacl | |
parent | 12a87df1b63f56e596d03fc9013a2a697bc57cc0 (diff) | |
download | chromium_src-8b12bb8af86c39409c215e557074b0e6cbe6212f.zip chromium_src-8b12bb8af86c39409c215e557074b0e6cbe6212f.tar.gz chromium_src-8b12bb8af86c39409c215e557074b0e6cbe6212f.tar.bz2 |
Refactoring: Split NaClListener into two delegated classes.
Currently, NaClListener has supports two modes, SFI and non-SFI.
As a preparation of newlib switching of non-SFI mode, this CL splits into
each delegate class, so that, we can easily build non-SFI related code
only by PNaCl toolchain.
BUG=358465
TEST=Ran trybots.
CQ_EXTRA_TRYBOTS=tryserver.chromium.linux:linux_rel_precise32
Review URL: https://codereview.chromium.org/439713002
Cr-Commit-Position: refs/heads/master@{#288271}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288271 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/nacl')
-rw-r--r-- | components/nacl/loader/nacl_helper_linux.cc | 15 | ||||
-rw-r--r-- | components/nacl/loader/nacl_listener.cc | 123 | ||||
-rw-r--r-- | components/nacl/loader/nacl_listener.h | 11 | ||||
-rw-r--r-- | components/nacl/loader/nacl_trusted_listener.cc | 19 | ||||
-rw-r--r-- | components/nacl/loader/nacl_trusted_listener.h | 5 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/nonsfi_listener.cc | 150 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/nonsfi_listener.h | 53 |
7 files changed, 232 insertions, 144 deletions
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc index 8c042d0..9789199 100644 --- a/components/nacl/loader/nacl_helper_linux.cc +++ b/components/nacl/loader/nacl_helper_linux.cc @@ -35,6 +35,7 @@ #include "components/nacl/common/nacl_switches.h" #include "components/nacl/loader/nacl_listener.h" #include "components/nacl/loader/nonsfi/irt_exception_handling.h" +#include "components/nacl/loader/nonsfi/nonsfi_listener.h" #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" #include "content/public/common/child_process_sandbox_support_linux.h" #include "content/public/common/content_descriptors.h" @@ -106,11 +107,15 @@ void BecomeNaClLoader(base::ScopedFD browser_fd, browser_fd.release()); base::MessageLoopForIO main_message_loop; - NaClListener listener; - listener.set_uses_nonsfi_mode(uses_nonsfi_mode); - listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size); - listener.set_number_of_cores(system_info.number_of_cores); - listener.Listen(); + if (uses_nonsfi_mode) { + nacl::nonsfi::NonSfiListener listener; + listener.Listen(); + } else { + NaClListener listener; + listener.set_prereserved_sandbox_size(system_info.prereserved_sandbox_size); + listener.set_number_of_cores(system_info.number_of_cores); + listener.Listen(); + } _exit(0); } diff --git a/components/nacl/loader/nacl_listener.cc b/components/nacl/loader/nacl_listener.cc index 433d941..d7c97ad 100644 --- a/components/nacl/loader/nacl_listener.cc +++ b/components/nacl/loader/nacl_listener.cc @@ -35,10 +35,7 @@ #endif #if defined(OS_LINUX) -#include "components/nacl/loader/nonsfi/irt_random.h" -#include "components/nacl/loader/nonsfi/nonsfi_main.h" #include "content/public/common/child_process_sandbox_support_linux.h" -#include "ppapi/nacl_irt/plugin_startup.h" #endif #if defined(OS_WIN) @@ -207,7 +204,6 @@ class BrowserValidationDBProxy : public NaClValidationDB { NaClListener::NaClListener() : shutdown_event_(true, false), io_thread_("NaCl_IOThread"), - uses_nonsfi_mode_(false), #if defined(OS_LINUX) prereserved_sandbox_size_(0), #endif @@ -265,11 +261,6 @@ bool NaClListener::OnMessageReceived(const IPC::Message& msg) { } void NaClListener::OnStart(const nacl::NaClStartParams& params) { - if (uses_nonsfi_mode_) { - StartNonSfi(params); - return; - } - #if defined(OS_LINUX) || defined(OS_MACOSX) int urandom_fd = dup(base::GetUrandomFD()); if (urandom_fd < 0) { @@ -303,11 +294,14 @@ void NaClListener::OnStart(const nacl::NaClStartParams& params) { nap, NACL_CHROME_DESC_BASE + 1); } - IPC::ChannelHandle trusted_renderer_handle = CreateTrustedListener( - io_thread_.message_loop_proxy(), &shutdown_event_); + 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_renderer_handle, IPC::ChannelHandle()))) + browser_handle, + ppapi_renderer_handle, + trusted_listener_->TakeClientChannelHandle(), + IPC::ChannelHandle()))) LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost."; std::vector<nacl::FileDescriptor> handles = params.handles; @@ -408,106 +402,3 @@ void NaClListener::OnStart(const nacl::NaClStartParams& params) { NaClChromeMainStartApp(nap, args); } - -void NaClListener::StartNonSfi(const nacl::NaClStartParams& params) { -#if !defined(OS_LINUX) - NOTREACHED() << "Non-SFI NaCl is only supported on Linux"; -#else - // Random number source initialization. - nacl::nonsfi::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. - IPC::ChannelHandle trusted_renderer_handle = CreateTrustedListener( - io_thread_.message_loop_proxy(), &shutdown_event_); - if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated( - browser_handle, ppapi_renderer_handle, - trusted_renderer_handle, 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); - nacl::nonsfi::MainStart( - IPC::PlatformFileForTransitToPlatformFile(params.nexe_file)); -#endif // defined(OS_LINUX) -} - -IPC::ChannelHandle NaClListener::CreateTrustedListener( - base::MessageLoopProxy* message_loop_proxy, - base::WaitableEvent* shutdown_event) { - // The argument passed to GenerateVerifiedChannelID() here MUST be "nacl". - // Using an alternate channel name prevents the pipe from being created on - // Windows when the sandbox is enabled. - IPC::ChannelHandle trusted_renderer_handle = - IPC::Channel::GenerateVerifiedChannelID("nacl"); - trusted_listener_ = new NaClTrustedListener( - trusted_renderer_handle, io_thread_.message_loop_proxy().get()); -#if defined(OS_POSIX) - trusted_renderer_handle.socket = base::FileDescriptor( - trusted_listener_->TakeClientFileDescriptor(), true); -#endif - return trusted_renderer_handle; -} diff --git a/components/nacl/loader/nacl_listener.h b/components/nacl/loader/nacl_listener.h index 6ca1ec2..31a0048 100644 --- a/components/nacl/loader/nacl_listener.h +++ b/components/nacl/loader/nacl_listener.h @@ -34,9 +34,6 @@ class NaClListener : public IPC::Listener { bool Send(IPC::Message* msg); - void set_uses_nonsfi_mode(bool uses_nonsfi_mode) { - uses_nonsfi_mode_ = uses_nonsfi_mode; - } #if defined(OS_LINUX) void set_prereserved_sandbox_size(size_t prereserved_sandbox_size) { prereserved_sandbox_size_ = prereserved_sandbox_size; @@ -53,13 +50,6 @@ class NaClListener : public IPC::Listener { void OnStart(const nacl::NaClStartParams& params); - // Non-SFI version of OnStart(). - void StartNonSfi(const nacl::NaClStartParams& params); - - IPC::ChannelHandle CreateTrustedListener( - base::MessageLoopProxy* message_loop_proxy, - base::WaitableEvent* shutdown_event); - // A channel back to the browser. scoped_ptr<IPC::SyncChannel> channel_; @@ -69,7 +59,6 @@ class NaClListener : public IPC::Listener { base::WaitableEvent shutdown_event_; base::Thread io_thread_; - bool uses_nonsfi_mode_; #if defined(OS_LINUX) size_t prereserved_sandbox_size_; #endif diff --git a/components/nacl/loader/nacl_trusted_listener.cc b/components/nacl/loader/nacl_trusted_listener.cc index 5f6410a..125f146 100644 --- a/components/nacl/loader/nacl_trusted_listener.cc +++ b/components/nacl/loader/nacl_trusted_listener.cc @@ -8,22 +8,23 @@ NaClTrustedListener::NaClTrustedListener( const IPC::ChannelHandle& handle, - base::SingleThreadTaskRunner* ipc_task_runner) { - channel_proxy_ = IPC::ChannelProxy::Create( - handle, - IPC::Channel::MODE_SERVER, - this, - ipc_task_runner).Pass(); + base::SingleThreadTaskRunner* ipc_task_runner) + : channel_handle_(handle), + channel_proxy_(IPC::ChannelProxy::Create( + handle, IPC::Channel::MODE_SERVER, this, ipc_task_runner)) { } NaClTrustedListener::~NaClTrustedListener() { } +IPC::ChannelHandle NaClTrustedListener::TakeClientChannelHandle() { + IPC::ChannelHandle handle = channel_handle_; #if defined(OS_POSIX) -int NaClTrustedListener::TakeClientFileDescriptor() { - return channel_proxy_->TakeClientFileDescriptor(); -} + handle.socket = + base::FileDescriptor(channel_proxy_->TakeClientFileDescriptor(), true); #endif + return handle; +} bool NaClTrustedListener::OnMessageReceived(const IPC::Message& msg) { return false; diff --git a/components/nacl/loader/nacl_trusted_listener.h b/components/nacl/loader/nacl_trusted_listener.h index 4819e05..bb66b42 100644 --- a/components/nacl/loader/nacl_trusted_listener.h +++ b/components/nacl/loader/nacl_trusted_listener.h @@ -20,9 +20,7 @@ class NaClTrustedListener : public base::RefCounted<NaClTrustedListener>, NaClTrustedListener(const IPC::ChannelHandle& handle, base::SingleThreadTaskRunner* ipc_task_runner); -#if defined(OS_POSIX) - int TakeClientFileDescriptor(); -#endif + IPC::ChannelHandle TakeClientChannelHandle(); // Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -33,6 +31,7 @@ class NaClTrustedListener : public base::RefCounted<NaClTrustedListener>, private: friend class base::RefCounted<NaClTrustedListener>; virtual ~NaClTrustedListener(); + IPC::ChannelHandle channel_handle_; scoped_ptr<IPC::ChannelProxy> channel_proxy_; DISALLOW_COPY_AND_ASSIGN(NaClTrustedListener); diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.cc b/components/nacl/loader/nonsfi/nonsfi_listener.cc new file mode 100644 index 0000000..839772c --- /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 diff --git a/components/nacl/loader/nonsfi/nonsfi_listener.h b/components/nacl/loader/nonsfi/nonsfi_listener.h new file mode 100644 index 0000000..a2acc61 --- /dev/null +++ b/components/nacl/loader/nonsfi/nonsfi_listener.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef COMPONENTS_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_ +#define COMPONENTS_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_ + +#include "base/macros.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "ipc/ipc_listener.h" + +namespace IPC { +class Message; +class SyncChannel; +} // namespace IPC + +class NaClTrustedListener; + +namespace nacl { + +struct NaClStartParams; + +namespace nonsfi { + +class NonSfiListener : public IPC::Listener { + public: + NonSfiListener(); + virtual ~NonSfiListener(); + + // Listen for a request to launch a non-SFI NaCl module. + void Listen(); + bool Send(IPC::Message* msg); + + private: + virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE; + void OnStart(const nacl::NaClStartParams& params); + + base::Thread io_thread_; + base::WaitableEvent shutdown_event_; + scoped_ptr<IPC::SyncChannel> channel_; + scoped_refptr<NaClTrustedListener> trusted_listener_; + + DISALLOW_COPY_AND_ASSIGN(NonSfiListener); +}; + +} // namespace nonsfi +} // namespace nacl + +#endif // COMPONENTS_NACL_LOADER_NONSFI_NONSFI_LISTENER_H_ |