125b3c049e70834cf33790a28643ab058b507b35cBen Cheng// Copyright 2014 The Chromium Authors. All rights reserved.
225b3c049e70834cf33790a28643ab058b507b35cBen Cheng// Use of this source code is governed by a BSD-style license that can be
325b3c049e70834cf33790a28643ab058b507b35cBen Cheng// found in the LICENSE file.
425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/loader/nonsfi/nonsfi_listener.h"
625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "base/command_line.h"
825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "base/file_descriptor_posix.h"
925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "base/logging.h"
1025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "base/message_loop/message_loop.h"
1125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "base/rand_util.h"
1225b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/common/nacl_messages.h"
1325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/common/nacl_types.h"
1425b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/loader/nacl_trusted_listener.h"
1525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/loader/nonsfi/irt_random.h"
1625b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "components/nacl/loader/nonsfi/nonsfi_main.h"
1725b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "ipc/ipc_channel.h"
1825b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "ipc/ipc_channel_handle.h"
1925b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "ipc/ipc_switches.h"
2025b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "ipc/ipc_sync_channel.h"
2125b3c049e70834cf33790a28643ab058b507b35cBen Cheng#include "ppapi/nacl_irt/plugin_startup.h"
2225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2325b3c049e70834cf33790a28643ab058b507b35cBen Cheng#if !defined(OS_LINUX)
2425b3c049e70834cf33790a28643ab058b507b35cBen Cheng# error "non-SFI mode is supported only on linux."
2525b3c049e70834cf33790a28643ab058b507b35cBen Cheng#endif
2625b3c049e70834cf33790a28643ab058b507b35cBen Cheng
2725b3c049e70834cf33790a28643ab058b507b35cBen Chengnamespace nacl {
2825b3c049e70834cf33790a28643ab058b507b35cBen Chengnamespace nonsfi {
2925b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3025b3c049e70834cf33790a28643ab058b507b35cBen ChengNonSfiListener::NonSfiListener() : io_thread_("NaCl_IOThread"),
3125b3c049e70834cf33790a28643ab058b507b35cBen Cheng                                   shutdown_event_(true, false) {
3225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  io_thread_.StartWithOptions(
3325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
3425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
3525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3625b3c049e70834cf33790a28643ab058b507b35cBen ChengNonSfiListener::~NonSfiListener() {
3725b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
3825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
3925b3c049e70834cf33790a28643ab058b507b35cBen Chengvoid NonSfiListener::Listen() {
4025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  channel_ = IPC::SyncChannel::Create(
4125b3c049e70834cf33790a28643ab058b507b35cBen Cheng      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
4225b3c049e70834cf33790a28643ab058b507b35cBen Cheng          switches::kProcessChannelID),
4325b3c049e70834cf33790a28643ab058b507b35cBen Cheng      IPC::Channel::MODE_CLIENT,
4425b3c049e70834cf33790a28643ab058b507b35cBen Cheng      this,  // As a Listener.
4525b3c049e70834cf33790a28643ab058b507b35cBen Cheng      io_thread_.message_loop_proxy().get(),
4625b3c049e70834cf33790a28643ab058b507b35cBen Cheng      true,  // Create pipe now.
4725b3c049e70834cf33790a28643ab058b507b35cBen Cheng      &shutdown_event_);
4825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  base::MessageLoop::current()->Run();
4925b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
5025b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5125b3c049e70834cf33790a28643ab058b507b35cBen Chengbool NonSfiListener::Send(IPC::Message* msg) {
5225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  DCHECK(channel_.get() != NULL);
5325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return channel_->Send(msg);
5425b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
5525b3c049e70834cf33790a28643ab058b507b35cBen Cheng
5625b3c049e70834cf33790a28643ab058b507b35cBen Chengbool NonSfiListener::OnMessageReceived(const IPC::Message& msg) {
5725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  bool handled = true;
5825b3c049e70834cf33790a28643ab058b507b35cBen Cheng  IPC_BEGIN_MESSAGE_MAP(NonSfiListener, msg)
5925b3c049e70834cf33790a28643ab058b507b35cBen Cheng      IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart)
6025b3c049e70834cf33790a28643ab058b507b35cBen Cheng      IPC_MESSAGE_UNHANDLED(handled = false)
6125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  IPC_END_MESSAGE_MAP()
6225b3c049e70834cf33790a28643ab058b507b35cBen Cheng  return handled;
6325b3c049e70834cf33790a28643ab058b507b35cBen Cheng}
6425b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6525b3c049e70834cf33790a28643ab058b507b35cBen Chengvoid NonSfiListener::OnStart(const nacl::NaClStartParams& params) {
6625b3c049e70834cf33790a28643ab058b507b35cBen Cheng  // Random number source initialization.
6725b3c049e70834cf33790a28643ab058b507b35cBen Cheng  SetUrandomFd(base::GetUrandomFD());
6825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
6925b3c049e70834cf33790a28643ab058b507b35cBen Cheng  IPC::ChannelHandle browser_handle;
7025b3c049e70834cf33790a28643ab058b507b35cBen Cheng  IPC::ChannelHandle ppapi_renderer_handle;
7125b3c049e70834cf33790a28643ab058b507b35cBen Cheng  IPC::ChannelHandle manifest_service_handle;
7225b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7325b3c049e70834cf33790a28643ab058b507b35cBen Cheng  if (params.enable_ipc_proxy) {
7425b3c049e70834cf33790a28643ab058b507b35cBen Cheng    browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl");
7525b3c049e70834cf33790a28643ab058b507b35cBen Cheng    ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl");
7625b3c049e70834cf33790a28643ab058b507b35cBen Cheng    manifest_service_handle =
7725b3c049e70834cf33790a28643ab058b507b35cBen Cheng        IPC::Channel::GenerateVerifiedChannelID("nacl");
7825b3c049e70834cf33790a28643ab058b507b35cBen Cheng
7925b3c049e70834cf33790a28643ab058b507b35cBen Cheng    // In non-SFI mode, we neither intercept nor rewrite the message using
8025b3c049e70834cf33790a28643ab058b507b35cBen Cheng    // NaClIPCAdapter, and the channels are connected between the plugin and
8125b3c049e70834cf33790a28643ab058b507b35cBen Cheng    // the hosts directly. So, the IPC::Channel instances will be created in
8225b3c049e70834cf33790a28643ab058b507b35cBen Cheng    // the plugin side, because the IPC::Listener needs to live on the
83    // plugin's main thread. However, on initialization (i.e. before loading
84    // the plugin binary), the FD needs to be passed to the hosts. So, here
85    // we create raw FD pairs, and pass the client side FDs to the hosts,
86    // and the server side FDs to the plugin.
87    int browser_server_ppapi_fd;
88    int browser_client_ppapi_fd;
89    int renderer_server_ppapi_fd;
90    int renderer_client_ppapi_fd;
91    int manifest_service_server_fd;
92    int manifest_service_client_fd;
93    if (!IPC::SocketPair(
94            &browser_server_ppapi_fd, &browser_client_ppapi_fd) ||
95        !IPC::SocketPair(
96            &renderer_server_ppapi_fd, &renderer_client_ppapi_fd) ||
97        !IPC::SocketPair(
98            &manifest_service_server_fd, &manifest_service_client_fd)) {
99      LOG(ERROR) << "Failed to create sockets for IPC.";
100      return;
101    }
102
103    // Set the plugin IPC channel FDs.
104    ppapi::SetIPCFileDescriptors(browser_server_ppapi_fd,
105                                 renderer_server_ppapi_fd,
106                                 manifest_service_server_fd);
107    ppapi::StartUpPlugin();
108
109    // Send back to the client side IPC channel FD to the host.
110    browser_handle.socket =
111        base::FileDescriptor(browser_client_ppapi_fd, true);
112    ppapi_renderer_handle.socket =
113        base::FileDescriptor(renderer_client_ppapi_fd, true);
114    manifest_service_handle.socket =
115        base::FileDescriptor(manifest_service_client_fd, true);
116  }
117
118  // TODO(teravest): Do we plan on using this renderer handle for nexe loading
119  // for non-SFI? Right now, passing an empty channel handle instead causes
120  // hangs, so we'll keep it.
121  trusted_listener_ = new NaClTrustedListener(
122      IPC::Channel::GenerateVerifiedChannelID("nacl"),
123      io_thread_.message_loop_proxy().get(),
124      &shutdown_event_);
125  if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated(
126          browser_handle,
127          ppapi_renderer_handle,
128          trusted_listener_->TakeClientChannelHandle(),
129          manifest_service_handle)))
130    LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost.";
131
132  // Ensure that the validation cache key (used as an extra input to the
133  // validation cache's hashing) isn't exposed accidentally.
134  CHECK(!params.validation_cache_enabled);
135  CHECK(params.validation_cache_key.size() == 0);
136  CHECK(params.version.size() == 0);
137  // Ensure that a debug stub FD isn't passed through accidentally.
138  CHECK(!params.enable_debug_stub);
139  CHECK(params.debug_stub_server_bound_socket.fd == -1);
140
141  CHECK(!params.uses_irt);
142  CHECK(params.handles.empty());
143
144  CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit());
145  CHECK(params.nexe_token_lo == 0);
146  CHECK(params.nexe_token_hi == 0);
147  MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file));
148}
149
150}  // namespace nonsfi
151}  // namespace nacl
152