Commit 8b12bb8a authored by hidehiko@chromium.org's avatar hidehiko@chromium.org

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
parent 12a87df1
......@@ -283,6 +283,8 @@
'nacl/loader/nonsfi/irt_resource_open.cc',
'nacl/loader/nonsfi/irt_thread.cc',
'nacl/loader/nonsfi/irt_util.h',
'nacl/loader/nonsfi/nonsfi_listener.cc',
'nacl/loader/nonsfi/nonsfi_listener.h',
'nacl/loader/nonsfi/nonsfi_main.cc',
'nacl/loader/nonsfi/nonsfi_main.h',
'nacl/loader/nonsfi/nonsfi_sandbox.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);
}
......
......@@ -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;
}
......@@ -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
......
......@@ -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;
......
......@@ -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);
......
// 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
// 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_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment