blob: 138bb08580ac6390da5bea6b917b31cdd629ab12 [file] [log] [blame]
[email protected]4bdde602010-06-16 03:17:351// Copyright (c) 2010 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]d5207642010-12-14 00:24:2716#include "chrome/browser/renderer_host/render_message_filter.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]d032f492009-09-29 00:33:4622#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5223#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]d032f492009-09-29 00:33:4624
[email protected]d032f492009-09-29 00:33:4625#if defined(OS_POSIX)
26#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3527#elif defined(OS_WIN)
28#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]d032f492009-09-29 00:33:4629#endif
30
[email protected]c47ec402010-07-29 10:20:4931namespace {
32
[email protected]ba077002010-09-27 15:22:3033#if !defined(DISABLE_NACL)
[email protected]c47ec402010-07-29 10:20:4934void SetCloseOnExec(nacl::Handle fd) {
35#if defined(OS_POSIX)
36 int flags = fcntl(fd, F_GETFD);
37 CHECK(flags != -1);
38 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
39 CHECK(rc == 0);
40#endif
41}
[email protected]ba077002010-09-27 15:22:3042#endif
[email protected]c47ec402010-07-29 10:20:4943
44} // namespace
45
[email protected]1d8a3d1f2011-02-19 07:11:5246struct NaClProcessHost::NaClInternal {
47 std::vector<nacl::Handle> sockets_for_renderer;
48 std::vector<nacl::Handle> sockets_for_sel_ldr;
49};
50
[email protected]d032f492009-09-29 00:33:4651NaClProcessHost::NaClProcessHost(
[email protected]f08e47d2009-10-15 21:46:1552 ResourceDispatcherHost *resource_dispatcher_host,
53 const std::wstring& url)
[email protected]d27893f62010-07-03 05:47:4254 : BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
[email protected]fb1277e82009-11-21 20:32:3055 resource_dispatcher_host_(resource_dispatcher_host),
56 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:5257 internal_(new NaClInternal()),
[email protected]103607e2010-02-01 18:57:0958 running_on_wow64_(false) {
[email protected]f08e47d2009-10-15 21:46:1559 set_name(url);
[email protected]103607e2010-02-01 18:57:0960#if defined(OS_WIN)
61 CheckIsWow64();
62#endif
[email protected]d032f492009-09-29 00:33:4663}
64
[email protected]fb1277e82009-11-21 20:32:3065NaClProcessHost::~NaClProcessHost() {
66 if (!reply_msg_)
67 return;
68
[email protected]990b29e2010-07-29 12:53:4769 // nacl::Close() is not available at link time if DISABLE_NACL is
70 // defined, but we still compile a bunch of other code from this
71 // file anyway. TODO(mseaborn): Make this less messy.
72#ifndef DISABLE_NACL
[email protected]1d8a3d1f2011-02-19 07:11:5273 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
74 nacl::Close(internal_->sockets_for_renderer[i]);
[email protected]c47ec402010-07-29 10:20:4975 }
[email protected]1d8a3d1f2011-02-19 07:11:5276 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
77 nacl::Close(internal_->sockets_for_sel_ldr[i]);
[email protected]c47ec402010-07-29 10:20:4978 }
[email protected]990b29e2010-07-29 12:53:4779#endif
[email protected]c47ec402010-07-29 10:20:4980
[email protected]fb1277e82009-11-21 20:32:3081 // OnProcessLaunched didn't get called because the process couldn't launch.
82 // Don't keep the renderer hanging.
83 reply_msg_->set_reply_error();
[email protected]d5207642010-12-14 00:24:2784 render_message_filter_->Send(reply_msg_);
[email protected]fb1277e82009-11-21 20:32:3085}
86
[email protected]d5207642010-12-14 00:24:2787bool NaClProcessHost::Launch(RenderMessageFilter* render_message_filter,
[email protected]c47ec402010-07-29 10:20:4988 int socket_count,
[email protected]fb1277e82009-11-21 20:32:3089 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3190#ifdef DISABLE_NACL
91 NOTIMPLEMENTED() << "Native Client disabled at build time";
92 return false;
93#else
[email protected]c47ec402010-07-29 10:20:4994 // Place an arbitrary limit on the number of sockets to limit
95 // exposure in case the renderer is compromised. We can increase
96 // this if necessary.
97 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:4698 return false;
[email protected]c47ec402010-07-29 10:20:4999 }
100
101 // Rather than creating a socket pair in the renderer, and passing
102 // one side through the browser to sel_ldr, socket pairs are created
103 // in the browser and then passed to the renderer and sel_ldr.
104 //
105 // This is mainly for the benefit of Windows, where sockets cannot
106 // be passed in messages, but are copied via DuplicateHandle().
107 // This means the sandboxed renderer cannot send handles to the
108 // browser process.
109
110 for (int i = 0; i < socket_count; i++) {
111 nacl::Handle pair[2];
112 // Create a connected socket
113 if (nacl::SocketPair(pair) == -1)
114 return false;
[email protected]1d8a3d1f2011-02-19 07:11:52115 internal_->sockets_for_renderer.push_back(pair[0]);
116 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49117 SetCloseOnExec(pair[0]);
118 SetCloseOnExec(pair[1]);
119 }
[email protected]d032f492009-09-29 00:33:46120
121 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30122 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46123 return false;
124 }
[email protected]9ec74462010-10-28 16:48:05125 UmaNaclHistogramEnumeration(NACL_STARTED);
[email protected]d5207642010-12-14 00:24:27126 render_message_filter_ = render_message_filter;
[email protected]fb1277e82009-11-21 20:32:30127 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15128
[email protected]d032f492009-09-29 00:33:46129 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31130#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46131}
132
[email protected]fb1277e82009-11-21 20:32:30133bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46134 if (!CreateChannel())
135 return false;
136
137 // Build command line for nacl.
[email protected]7c4ea142010-01-26 05:15:42138 FilePath exe_path = GetChildPath(true);
[email protected]fb1277e82009-11-21 20:32:30139 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46140 return false;
141
[email protected]fb1277e82009-11-21 20:32:30142 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09143 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13144
[email protected]05076ba22010-07-30 05:59:57145 cmd_line->AppendSwitchASCII(switches::kProcessType,
146 switches::kNaClLoaderProcess);
[email protected]d032f492009-09-29 00:33:46147
[email protected]05076ba22010-07-30 05:59:57148 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]d032f492009-09-29 00:33:46149
[email protected]67842522011-01-14 18:27:37150 SetCrashReporterCommandLine(cmd_line);
151
[email protected]103607e2010-02-01 18:57:09152 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46153#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09154 if (running_on_wow64_) {
155 NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_);
[email protected]2a4d7542010-03-17 02:06:33156 return NaClBrokerService::GetInstance()->LaunchLoader(this,
157 ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35158 } else {
[email protected]d27893f62010-07-03 05:47:42159 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35160 }
[email protected]103607e2010-02-01 18:57:09161#elif defined(OS_POSIX)
[email protected]d27893f62010-07-03 05:47:42162 BrowserChildProcessHost::Launch(true, // use_zygote
163 base::environment_vector(),
164 cmd_line);
[email protected]103607e2010-02-01 18:57:09165#endif
[email protected]d032f492009-09-29 00:33:46166
[email protected]fb1277e82009-11-21 20:32:30167 return true;
[email protected]d032f492009-09-29 00:33:46168}
169
[email protected]103607e2010-02-01 18:57:09170void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
171 set_handle(handle);
172 OnProcessLaunched();
173}
174
[email protected]443b80e2010-12-14 00:42:23175base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
176 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38177 if (running_on_wow64_)
[email protected]443b80e2010-12-14 00:42:23178 return base::GetTerminationStatus(handle(), exit_code);
179 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
[email protected]103607e2010-02-01 18:57:09180}
181
[email protected]16e70ae2010-03-08 21:41:28182void NaClProcessHost::OnChildDied() {
183#if defined(OS_WIN)
184 NaClBrokerService::GetInstance()->OnLoaderDied();
185#endif
[email protected]d27893f62010-07-03 05:47:42186 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28187}
188
[email protected]fb1277e82009-11-21 20:32:30189void NaClProcessHost::OnProcessLaunched() {
[email protected]c47ec402010-07-29 10:20:49190 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30191 base::ProcessHandle nacl_process_handle;
[email protected]fb1277e82009-11-21 20:32:30192
[email protected]1d8a3d1f2011-02-19 07:11:52193 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49194#if defined(OS_WIN)
195 // Copy the handle into the renderer process.
196 HANDLE handle_in_renderer;
197 DuplicateHandle(base::GetCurrentProcessHandle(),
[email protected]1d8a3d1f2011-02-19 07:11:52198 reinterpret_cast<HANDLE>(
199 internal_->sockets_for_renderer[i]),
[email protected]8e2b6472010-12-15 22:19:48200 render_message_filter_->peer_handle(),
[email protected]c47ec402010-07-29 10:20:49201 &handle_in_renderer,
202 GENERIC_READ | GENERIC_WRITE,
203 FALSE,
204 DUPLICATE_CLOSE_SOURCE);
205 handles_for_renderer.push_back(
206 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
207#else
208 // No need to dup the imc_handle - we don't pass it anywhere else so
209 // it cannot be closed.
210 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52211 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49212 imc_handle.auto_close = true;
213 handles_for_renderer.push_back(imc_handle);
214#endif
215 }
216
217#if defined(OS_WIN)
218 // Copy the process handle into the renderer process.
[email protected]fb1277e82009-11-21 20:32:30219 DuplicateHandle(base::GetCurrentProcessHandle(),
220 handle(),
[email protected]8e2b6472010-12-15 22:19:48221 render_message_filter_->peer_handle(),
[email protected]fb1277e82009-11-21 20:32:30222 &nacl_process_handle,
223 PROCESS_DUP_HANDLE,
224 FALSE,
225 0);
[email protected]fb1277e82009-11-21 20:32:30226#else
[email protected]fb1277e82009-11-21 20:32:30227 // We use pid as process handle on Posix
228 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30229#endif
230
231 // Get the pid of the NaCl process
232 base::ProcessId nacl_process_id = base::GetProcId(handle());
233
234 ViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49235 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]d5207642010-12-14 00:24:27236 render_message_filter_->Send(reply_msg_);
237 render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30238 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52239 internal_->sockets_for_renderer.clear();
[email protected]fb1277e82009-11-21 20:32:30240
241 SendStartMessage();
242}
243
244void NaClProcessHost::SendStartMessage() {
[email protected]c47ec402010-07-29 10:20:49245 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
[email protected]1d8a3d1f2011-02-19 07:11:52246 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]d032f492009-09-29 00:33:46247#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49248 HANDLE channel;
249 if (!DuplicateHandle(GetCurrentProcess(),
[email protected]1d8a3d1f2011-02-19 07:11:52250 reinterpret_cast<HANDLE>(
251 internal_->sockets_for_sel_ldr[i]),
[email protected]c47ec402010-07-29 10:20:49252 handle(),
253 &channel,
254 GENERIC_READ | GENERIC_WRITE,
255 FALSE, DUPLICATE_CLOSE_SOURCE)) {
256 return;
257 }
258 handles_for_sel_ldr.push_back(
259 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46260#else
[email protected]c47ec402010-07-29 10:20:49261 nacl::FileDescriptor channel;
[email protected]1d8a3d1f2011-02-19 07:11:52262 channel.fd = dup(internal_->sockets_for_sel_ldr[i]);
[email protected]2c68bf032010-11-11 23:16:30263 if (channel.fd < 0) {
264 LOG(ERROR) << "Failed to dup() a file descriptor";
265 return;
266 }
[email protected]c47ec402010-07-29 10:20:49267 channel.auto_close = true;
268 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46269#endif
[email protected]c47ec402010-07-29 10:20:49270 }
271
[email protected]2c68bf032010-11-11 23:16:30272#if defined(OS_MACOSX)
273 // For dynamic loading support, NaCl requires a file descriptor that
274 // was created in /tmp, since those created with shm_open() are not
275 // mappable with PROT_EXEC. Rather than requiring an extra IPC
276 // round trip out of the sandbox, we create an FD here.
277 base::SharedMemory memory_buffer;
278 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
279 LOG(ERROR) << "Failed to allocate memory buffer";
280 return;
281 }
282 nacl::FileDescriptor memory_fd;
283 memory_fd.fd = dup(memory_buffer.handle().fd);
284 if (memory_fd.fd < 0) {
285 LOG(ERROR) << "Failed to dup() a file descriptor";
286 return;
287 }
288 memory_fd.auto_close = true;
289 handles_for_sel_ldr.push_back(memory_fd);
290#endif
291
[email protected]c47ec402010-07-29 10:20:49292 Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
[email protected]1d8a3d1f2011-02-19 07:11:52293 internal_->sockets_for_sel_ldr.clear();
[email protected]d032f492009-09-29 00:33:46294}
295
[email protected]a95986a82010-12-24 06:19:28296bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
[email protected]d032f492009-09-29 00:33:46297 NOTREACHED() << "Invalid message with type = " << msg.type();
[email protected]a95986a82010-12-24 06:19:28298 return false;
[email protected]d032f492009-09-29 00:33:46299}
300
[email protected]e4be2dd2010-12-14 00:44:39301bool NaClProcessHost::CanShutdown() {
302 return true;
303}
304
[email protected]103607e2010-02-01 18:57:09305#if defined(OS_WIN)
306// TODO(gregoryd): invoke CheckIsWow64 only once, not for each NaClProcessHost
307typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
308void NaClProcessHost::CheckIsWow64() {
309 LPFN_ISWOW64PROCESS fnIsWow64Process;
310
311 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
312 GetModuleHandle(TEXT("kernel32")),
313 "IsWow64Process");
314
315 if (fnIsWow64Process != NULL) {
316 BOOL bIsWow64 = FALSE;
317 if (fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) {
318 if (bIsWow64) {
319 running_on_wow64_ = true;
320 }
321 }
322 }
323}
324#endif