blob: 2b97881c4ebe37e5aa3399a34c959f89ec9f0296 [file] [log] [blame]
[email protected]1e67c2b2011-03-04 01:17:371// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]d032f492009-09-29 00:33:462// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "build/build_config.h"
6
[email protected]e15a4fa2010-02-11 23:09:297#include "chrome/browser/nacl_host/nacl_process_host.h"
[email protected]d032f492009-09-29 00:33:468
9#if defined(OS_POSIX)
10#include <fcntl.h>
11#endif
12
[email protected]103607e2010-02-01 18:57:0913#include "base/command_line.h"
[email protected]9ec74462010-10-28 16:48:0514#include "base/metrics/nacl_histogram.h"
[email protected]be1ce6a72010-08-03 14:35:2215#include "base/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3716#include "base/win/windows_version.h"
[email protected]d032f492009-09-29 00:33:4617#include "chrome/common/chrome_switches.h"
18#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0919#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4620#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3021#include "chrome/common/render_messages.h"
[email protected]5de634712011-03-02 00:20:1922#include "content/browser/renderer_host/render_message_filter.h"
[email protected]d032f492009-09-29 00:33:4623#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5224#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]d032f492009-09-29 00:33:4625
[email protected]d032f492009-09-29 00:33:4626#if defined(OS_POSIX)
27#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3528#elif defined(OS_WIN)
29#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]d032f492009-09-29 00:33:4630#endif
31
[email protected]c47ec402010-07-29 10:20:4932namespace {
33
[email protected]ba077002010-09-27 15:22:3034#if !defined(DISABLE_NACL)
[email protected]c47ec402010-07-29 10:20:4935void SetCloseOnExec(nacl::Handle fd) {
36#if defined(OS_POSIX)
37 int flags = fcntl(fd, F_GETFD);
38 CHECK(flags != -1);
39 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
40 CHECK(rc == 0);
41#endif
42}
[email protected]ba077002010-09-27 15:22:3043#endif
[email protected]c47ec402010-07-29 10:20:4944
45} // namespace
46
[email protected]1d8a3d1f2011-02-19 07:11:5247struct NaClProcessHost::NaClInternal {
48 std::vector<nacl::Handle> sockets_for_renderer;
49 std::vector<nacl::Handle> sockets_for_sel_ldr;
50};
51
[email protected]d032f492009-09-29 00:33:4652NaClProcessHost::NaClProcessHost(
[email protected]f08e47d2009-10-15 21:46:1553 ResourceDispatcherHost *resource_dispatcher_host,
54 const std::wstring& url)
[email protected]d27893f62010-07-03 05:47:4255 : BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
[email protected]fb1277e82009-11-21 20:32:3056 resource_dispatcher_host_(resource_dispatcher_host),
57 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:5258 internal_(new NaClInternal()),
[email protected]103607e2010-02-01 18:57:0959 running_on_wow64_(false) {
[email protected]f08e47d2009-10-15 21:46:1560 set_name(url);
[email protected]103607e2010-02-01 18:57:0961#if defined(OS_WIN)
[email protected]1e67c2b2011-03-04 01:17:3762 running_on_wow64_ = (base::win::GetWOW64Status() == base::win::WOW64_ENABLED);
[email protected]103607e2010-02-01 18:57:0963#endif
[email protected]d032f492009-09-29 00:33:4664}
65
[email protected]fb1277e82009-11-21 20:32:3066NaClProcessHost::~NaClProcessHost() {
67 if (!reply_msg_)
68 return;
69
[email protected]990b29e2010-07-29 12:53:4770 // nacl::Close() is not available at link time if DISABLE_NACL is
71 // defined, but we still compile a bunch of other code from this
72 // file anyway. TODO(mseaborn): Make this less messy.
73#ifndef DISABLE_NACL
[email protected]1d8a3d1f2011-02-19 07:11:5274 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
75 nacl::Close(internal_->sockets_for_renderer[i]);
[email protected]c47ec402010-07-29 10:20:4976 }
[email protected]1d8a3d1f2011-02-19 07:11:5277 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
78 nacl::Close(internal_->sockets_for_sel_ldr[i]);
[email protected]c47ec402010-07-29 10:20:4979 }
[email protected]990b29e2010-07-29 12:53:4780#endif
[email protected]c47ec402010-07-29 10:20:4981
[email protected]fb1277e82009-11-21 20:32:3082 // OnProcessLaunched didn't get called because the process couldn't launch.
83 // Don't keep the renderer hanging.
84 reply_msg_->set_reply_error();
[email protected]d5207642010-12-14 00:24:2785 render_message_filter_->Send(reply_msg_);
[email protected]fb1277e82009-11-21 20:32:3086}
87
[email protected]d5207642010-12-14 00:24:2788bool NaClProcessHost::Launch(RenderMessageFilter* render_message_filter,
[email protected]c47ec402010-07-29 10:20:4989 int socket_count,
[email protected]fb1277e82009-11-21 20:32:3090 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3191#ifdef DISABLE_NACL
92 NOTIMPLEMENTED() << "Native Client disabled at build time";
93 return false;
94#else
[email protected]c47ec402010-07-29 10:20:4995 // Place an arbitrary limit on the number of sockets to limit
96 // exposure in case the renderer is compromised. We can increase
97 // this if necessary.
98 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:4699 return false;
[email protected]c47ec402010-07-29 10:20:49100 }
101
102 // Rather than creating a socket pair in the renderer, and passing
103 // one side through the browser to sel_ldr, socket pairs are created
104 // in the browser and then passed to the renderer and sel_ldr.
105 //
106 // This is mainly for the benefit of Windows, where sockets cannot
107 // be passed in messages, but are copied via DuplicateHandle().
108 // This means the sandboxed renderer cannot send handles to the
109 // browser process.
110
111 for (int i = 0; i < socket_count; i++) {
112 nacl::Handle pair[2];
113 // Create a connected socket
114 if (nacl::SocketPair(pair) == -1)
115 return false;
[email protected]1d8a3d1f2011-02-19 07:11:52116 internal_->sockets_for_renderer.push_back(pair[0]);
117 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49118 SetCloseOnExec(pair[0]);
119 SetCloseOnExec(pair[1]);
120 }
[email protected]d032f492009-09-29 00:33:46121
122 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30123 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46124 return false;
125 }
[email protected]9ec74462010-10-28 16:48:05126 UmaNaclHistogramEnumeration(NACL_STARTED);
[email protected]d5207642010-12-14 00:24:27127 render_message_filter_ = render_message_filter;
[email protected]fb1277e82009-11-21 20:32:30128 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15129
[email protected]d032f492009-09-29 00:33:46130 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31131#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46132}
133
[email protected]fb1277e82009-11-21 20:32:30134bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46135 if (!CreateChannel())
136 return false;
137
138 // Build command line for nacl.
[email protected]7c4ea142010-01-26 05:15:42139 FilePath exe_path = GetChildPath(true);
[email protected]fb1277e82009-11-21 20:32:30140 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46141 return false;
142
[email protected]fb1277e82009-11-21 20:32:30143 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09144 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13145
[email protected]05076ba22010-07-30 05:59:57146 cmd_line->AppendSwitchASCII(switches::kProcessType,
147 switches::kNaClLoaderProcess);
[email protected]d032f492009-09-29 00:33:46148
[email protected]05076ba22010-07-30 05:59:57149 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]d032f492009-09-29 00:33:46150
[email protected]67842522011-01-14 18:27:37151 SetCrashReporterCommandLine(cmd_line);
152
[email protected]103607e2010-02-01 18:57:09153 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46154#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09155 if (running_on_wow64_) {
156 NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_);
[email protected]2a4d7542010-03-17 02:06:33157 return NaClBrokerService::GetInstance()->LaunchLoader(this,
158 ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35159 } else {
[email protected]d27893f62010-07-03 05:47:42160 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35161 }
[email protected]103607e2010-02-01 18:57:09162#elif defined(OS_POSIX)
[email protected]d27893f62010-07-03 05:47:42163 BrowserChildProcessHost::Launch(true, // use_zygote
164 base::environment_vector(),
165 cmd_line);
[email protected]103607e2010-02-01 18:57:09166#endif
[email protected]d032f492009-09-29 00:33:46167
[email protected]fb1277e82009-11-21 20:32:30168 return true;
[email protected]d032f492009-09-29 00:33:46169}
170
[email protected]103607e2010-02-01 18:57:09171void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
172 set_handle(handle);
173 OnProcessLaunched();
174}
175
[email protected]443b80e2010-12-14 00:42:23176base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
177 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38178 if (running_on_wow64_)
[email protected]443b80e2010-12-14 00:42:23179 return base::GetTerminationStatus(handle(), exit_code);
180 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
[email protected]103607e2010-02-01 18:57:09181}
182
[email protected]16e70ae2010-03-08 21:41:28183void NaClProcessHost::OnChildDied() {
184#if defined(OS_WIN)
185 NaClBrokerService::GetInstance()->OnLoaderDied();
186#endif
[email protected]d27893f62010-07-03 05:47:42187 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28188}
189
[email protected]fb1277e82009-11-21 20:32:30190void NaClProcessHost::OnProcessLaunched() {
[email protected]c47ec402010-07-29 10:20:49191 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30192 base::ProcessHandle nacl_process_handle;
[email protected]fb1277e82009-11-21 20:32:30193
[email protected]1d8a3d1f2011-02-19 07:11:52194 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49195#if defined(OS_WIN)
196 // Copy the handle into the renderer process.
197 HANDLE handle_in_renderer;
198 DuplicateHandle(base::GetCurrentProcessHandle(),
[email protected]1d8a3d1f2011-02-19 07:11:52199 reinterpret_cast<HANDLE>(
200 internal_->sockets_for_renderer[i]),
[email protected]8e2b6472010-12-15 22:19:48201 render_message_filter_->peer_handle(),
[email protected]c47ec402010-07-29 10:20:49202 &handle_in_renderer,
203 GENERIC_READ | GENERIC_WRITE,
204 FALSE,
205 DUPLICATE_CLOSE_SOURCE);
206 handles_for_renderer.push_back(
207 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
208#else
209 // No need to dup the imc_handle - we don't pass it anywhere else so
210 // it cannot be closed.
211 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52212 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49213 imc_handle.auto_close = true;
214 handles_for_renderer.push_back(imc_handle);
215#endif
216 }
217
218#if defined(OS_WIN)
219 // Copy the process handle into the renderer process.
[email protected]fb1277e82009-11-21 20:32:30220 DuplicateHandle(base::GetCurrentProcessHandle(),
221 handle(),
[email protected]8e2b6472010-12-15 22:19:48222 render_message_filter_->peer_handle(),
[email protected]fb1277e82009-11-21 20:32:30223 &nacl_process_handle,
224 PROCESS_DUP_HANDLE,
225 FALSE,
226 0);
[email protected]fb1277e82009-11-21 20:32:30227#else
[email protected]fb1277e82009-11-21 20:32:30228 // We use pid as process handle on Posix
229 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30230#endif
231
232 // Get the pid of the NaCl process
233 base::ProcessId nacl_process_id = base::GetProcId(handle());
234
235 ViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49236 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]d5207642010-12-14 00:24:27237 render_message_filter_->Send(reply_msg_);
238 render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30239 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52240 internal_->sockets_for_renderer.clear();
[email protected]fb1277e82009-11-21 20:32:30241
242 SendStartMessage();
243}
244
245void NaClProcessHost::SendStartMessage() {
[email protected]c47ec402010-07-29 10:20:49246 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
[email protected]1d8a3d1f2011-02-19 07:11:52247 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]d032f492009-09-29 00:33:46248#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49249 HANDLE channel;
250 if (!DuplicateHandle(GetCurrentProcess(),
[email protected]1d8a3d1f2011-02-19 07:11:52251 reinterpret_cast<HANDLE>(
252 internal_->sockets_for_sel_ldr[i]),
[email protected]c47ec402010-07-29 10:20:49253 handle(),
254 &channel,
255 GENERIC_READ | GENERIC_WRITE,
256 FALSE, DUPLICATE_CLOSE_SOURCE)) {
257 return;
258 }
259 handles_for_sel_ldr.push_back(
260 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46261#else
[email protected]c47ec402010-07-29 10:20:49262 nacl::FileDescriptor channel;
[email protected]1d8a3d1f2011-02-19 07:11:52263 channel.fd = dup(internal_->sockets_for_sel_ldr[i]);
[email protected]2c68bf032010-11-11 23:16:30264 if (channel.fd < 0) {
265 LOG(ERROR) << "Failed to dup() a file descriptor";
266 return;
267 }
[email protected]c47ec402010-07-29 10:20:49268 channel.auto_close = true;
269 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46270#endif
[email protected]c47ec402010-07-29 10:20:49271 }
272
[email protected]2c68bf032010-11-11 23:16:30273#if defined(OS_MACOSX)
274 // For dynamic loading support, NaCl requires a file descriptor that
275 // was created in /tmp, since those created with shm_open() are not
276 // mappable with PROT_EXEC. Rather than requiring an extra IPC
277 // round trip out of the sandbox, we create an FD here.
278 base::SharedMemory memory_buffer;
279 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
280 LOG(ERROR) << "Failed to allocate memory buffer";
281 return;
282 }
283 nacl::FileDescriptor memory_fd;
284 memory_fd.fd = dup(memory_buffer.handle().fd);
285 if (memory_fd.fd < 0) {
286 LOG(ERROR) << "Failed to dup() a file descriptor";
287 return;
288 }
289 memory_fd.auto_close = true;
290 handles_for_sel_ldr.push_back(memory_fd);
291#endif
292
[email protected]c47ec402010-07-29 10:20:49293 Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
[email protected]1d8a3d1f2011-02-19 07:11:52294 internal_->sockets_for_sel_ldr.clear();
[email protected]d032f492009-09-29 00:33:46295}
296
[email protected]a95986a82010-12-24 06:19:28297bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
[email protected]d032f492009-09-29 00:33:46298 NOTREACHED() << "Invalid message with type = " << msg.type();
[email protected]a95986a82010-12-24 06:19:28299 return false;
[email protected]d032f492009-09-29 00:33:46300}
301
[email protected]e4be2dd2010-12-14 00:44:39302bool NaClProcessHost::CanShutdown() {
303 return true;
304}