blob: 839772cf5e6173312a3e096a6d1c039ecbdfbf65 [file] [log] [blame]
Torne (Richard Coles)6e8cce62014-08-19 13:00:08 +01001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/nacl/loader/nonsfi/nonsfi_listener.h"
6
7#include "base/command_line.h"
8#include "base/file_descriptor_posix.h"
9#include "base/logging.h"
10#include "base/message_loop/message_loop.h"
11#include "base/rand_util.h"
12#include "components/nacl/common/nacl_messages.h"
13#include "components/nacl/common/nacl_types.h"
14#include "components/nacl/loader/nacl_trusted_listener.h"
15#include "components/nacl/loader/nonsfi/irt_random.h"
16#include "components/nacl/loader/nonsfi/nonsfi_main.h"
17#include "ipc/ipc_channel.h"
18#include "ipc/ipc_channel_handle.h"
19#include "ipc/ipc_switches.h"
20#include "ipc/ipc_sync_channel.h"
21#include "ppapi/nacl_irt/plugin_startup.h"
22
23#if !defined(OS_LINUX)
24# error "non-SFI mode is supported only on linux."
25#endif
26
27namespace nacl {
28namespace nonsfi {
29
30NonSfiListener::NonSfiListener() : io_thread_("NaCl_IOThread"),
31 shutdown_event_(true, false) {
32 io_thread_.StartWithOptions(
33 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
34}
35
36NonSfiListener::~NonSfiListener() {
37}
38
39void NonSfiListener::Listen() {
40 channel_ = IPC::SyncChannel::Create(
41 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
42 switches::kProcessChannelID),
43 IPC::Channel::MODE_CLIENT,
44 this, // As a Listener.
45 io_thread_.message_loop_proxy().get(),
46 true, // Create pipe now.
47 &shutdown_event_);
48 base::MessageLoop::current()->Run();
49}
50
51bool NonSfiListener::Send(IPC::Message* msg) {
52 DCHECK(channel_.get() != NULL);
53 return channel_->Send(msg);
54}
55
56bool NonSfiListener::OnMessageReceived(const IPC::Message& msg) {
57 bool handled = true;
58 IPC_BEGIN_MESSAGE_MAP(NonSfiListener, msg)
59 IPC_MESSAGE_HANDLER(NaClProcessMsg_Start, OnStart)
60 IPC_MESSAGE_UNHANDLED(handled = false)
61 IPC_END_MESSAGE_MAP()
62 return handled;
63}
64
65void NonSfiListener::OnStart(const nacl::NaClStartParams& params) {
66 // Random number source initialization.
67 SetUrandomFd(base::GetUrandomFD());
68
69 IPC::ChannelHandle browser_handle;
70 IPC::ChannelHandle ppapi_renderer_handle;
71 IPC::ChannelHandle manifest_service_handle;
72
73 if (params.enable_ipc_proxy) {
74 browser_handle = IPC::Channel::GenerateVerifiedChannelID("nacl");
75 ppapi_renderer_handle = IPC::Channel::GenerateVerifiedChannelID("nacl");
76 manifest_service_handle =
77 IPC::Channel::GenerateVerifiedChannelID("nacl");
78
79 // In non-SFI mode, we neither intercept nor rewrite the message using
80 // NaClIPCAdapter, and the channels are connected between the plugin and
81 // the hosts directly. So, the IPC::Channel instances will be created in
82 // 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 if (!Send(new NaClProcessHostMsg_PpapiChannelsCreated(
125 browser_handle,
126 ppapi_renderer_handle,
127 trusted_listener_->TakeClientChannelHandle(),
128 manifest_service_handle)))
129 LOG(ERROR) << "Failed to send IPC channel handle to NaClProcessHost.";
130
131 // Ensure that the validation cache key (used as an extra input to the
132 // validation cache's hashing) isn't exposed accidentally.
133 CHECK(!params.validation_cache_enabled);
134 CHECK(params.validation_cache_key.size() == 0);
135 CHECK(params.version.size() == 0);
136 // Ensure that a debug stub FD isn't passed through accidentally.
137 CHECK(!params.enable_debug_stub);
138 CHECK(params.debug_stub_server_bound_socket.fd == -1);
139
140 CHECK(!params.uses_irt);
141 CHECK(params.handles.empty());
142
143 CHECK(params.nexe_file != IPC::InvalidPlatformFileForTransit());
144 CHECK(params.nexe_token_lo == 0);
145 CHECK(params.nexe_token_hi == 0);
146 MainStart(IPC::PlatformFileForTransitToPlatformFile(params.nexe_file));
147}
148
149} // namespace nonsfi
150} // namespace nacl