blob: 195a2fa21a04fb8ae024b7fad746dc6500ed0704 [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]30c1eea2011-10-17 18:40:3013#include "base/bind.h"
[email protected]103607e2010-02-01 18:57:0914#include "base/command_line.h"
[email protected]338466a82011-05-03 04:27:4315#include "base/path_service.h"
[email protected]a0a69bf2011-09-23 21:40:2816#include "base/stringprintf.h"
[email protected]be1ce6a72010-08-03 14:35:2217#include "base/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3718#include "base/win/windows_version.h"
[email protected]338466a82011-05-03 04:27:4319#include "chrome/common/chrome_paths.h"
[email protected]d032f492009-09-29 00:33:4620#include "chrome/common/chrome_switches.h"
21#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0922#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4623#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3024#include "chrome/common/render_messages.h"
[email protected]92d56412011-03-24 20:53:5225#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]d032f492009-09-29 00:33:4626#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5227#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]d032f492009-09-29 00:33:4628
[email protected]d032f492009-09-29 00:33:4629#if defined(OS_POSIX)
30#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3531#elif defined(OS_WIN)
32#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]d032f492009-09-29 00:33:4633#endif
34
[email protected]c47ec402010-07-29 10:20:4935namespace {
36
[email protected]ba077002010-09-27 15:22:3037#if !defined(DISABLE_NACL)
[email protected]c47ec402010-07-29 10:20:4938void SetCloseOnExec(nacl::Handle fd) {
39#if defined(OS_POSIX)
40 int flags = fcntl(fd, F_GETFD);
41 CHECK(flags != -1);
42 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
43 CHECK(rc == 0);
44#endif
45}
[email protected]ba077002010-09-27 15:22:3046#endif
[email protected]c47ec402010-07-29 10:20:4947
48} // namespace
49
[email protected]1d8a3d1f2011-02-19 07:11:5250struct NaClProcessHost::NaClInternal {
51 std::vector<nacl::Handle> sockets_for_renderer;
52 std::vector<nacl::Handle> sockets_for_sel_ldr;
53};
54
[email protected]1dbaaa702011-04-06 17:43:4255NaClProcessHost::NaClProcessHost(const std::wstring& url)
[email protected]5afcf6882011-04-08 20:11:1556 : BrowserChildProcessHost(NACL_LOADER_PROCESS),
[email protected]fb1277e82009-11-21 20:32:3057 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:5258 internal_(new NaClInternal()),
[email protected]338466a82011-05-03 04:27:4359 running_on_wow64_(false),
[email protected]30c1eea2011-10-17 18:40:3060 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
[email protected]68b9e72b2011-08-05 23:08:2261 set_name(WideToUTF16Hack(url));
[email protected]103607e2010-02-01 18:57:0962#if defined(OS_WIN)
[email protected]f481221192011-04-07 22:15:3463 running_on_wow64_ = (base::win::OSInfo::GetInstance()->wow64_status() ==
64 base::win::OSInfo::WOW64_ENABLED);
[email protected]103607e2010-02-01 18:57:0965#endif
[email protected]d032f492009-09-29 00:33:4666}
67
[email protected]fb1277e82009-11-21 20:32:3068NaClProcessHost::~NaClProcessHost() {
[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++) {
[email protected]909c2402011-05-09 11:39:0474 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) {
75 LOG(ERROR) << "nacl::Close() failed";
76 }
[email protected]c47ec402010-07-29 10:20:4977 }
[email protected]1d8a3d1f2011-02-19 07:11:5278 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]909c2402011-05-09 11:39:0479 if (nacl::Close(internal_->sockets_for_sel_ldr[i]) != 0) {
80 LOG(ERROR) << "nacl::Close() failed";
81 }
[email protected]c47ec402010-07-29 10:20:4982 }
[email protected]990b29e2010-07-29 12:53:4783#endif
[email protected]c47ec402010-07-29 10:20:4984
[email protected]909c2402011-05-09 11:39:0485 if (reply_msg_) {
86 // The process failed to launch for some reason.
87 // Don't keep the renderer hanging.
88 reply_msg_->set_reply_error();
89 chrome_render_message_filter_->Send(reply_msg_);
90 }
[email protected]fb1277e82009-11-21 20:32:3091}
92
[email protected]92d56412011-03-24 20:53:5293bool NaClProcessHost::Launch(
94 ChromeRenderMessageFilter* chrome_render_message_filter,
95 int socket_count,
96 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3197#ifdef DISABLE_NACL
98 NOTIMPLEMENTED() << "Native Client disabled at build time";
99 return false;
100#else
[email protected]c47ec402010-07-29 10:20:49101 // Place an arbitrary limit on the number of sockets to limit
102 // exposure in case the renderer is compromised. We can increase
103 // this if necessary.
104 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:46105 return false;
[email protected]c47ec402010-07-29 10:20:49106 }
107
108 // Rather than creating a socket pair in the renderer, and passing
109 // one side through the browser to sel_ldr, socket pairs are created
110 // in the browser and then passed to the renderer and sel_ldr.
111 //
112 // This is mainly for the benefit of Windows, where sockets cannot
113 // be passed in messages, but are copied via DuplicateHandle().
114 // This means the sandboxed renderer cannot send handles to the
115 // browser process.
116
117 for (int i = 0; i < socket_count; i++) {
118 nacl::Handle pair[2];
119 // Create a connected socket
120 if (nacl::SocketPair(pair) == -1)
121 return false;
[email protected]1d8a3d1f2011-02-19 07:11:52122 internal_->sockets_for_renderer.push_back(pair[0]);
123 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49124 SetCloseOnExec(pair[0]);
125 SetCloseOnExec(pair[1]);
126 }
[email protected]d032f492009-09-29 00:33:46127
128 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30129 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46130 return false;
131 }
[email protected]92d56412011-03-24 20:53:52132 chrome_render_message_filter_ = chrome_render_message_filter;
[email protected]fb1277e82009-11-21 20:32:30133 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15134
[email protected]d032f492009-09-29 00:33:46135 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31136#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46137}
138
[email protected]fb1277e82009-11-21 20:32:30139bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46140 if (!CreateChannel())
141 return false;
142
[email protected]e3fc75a2011-05-05 08:20:42143 CommandLine::StringType nacl_loader_prefix;
144#if defined(OS_POSIX)
145 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
146 switches::kNaClLoaderCmdPrefix);
147#endif // defined(OS_POSIX)
148
[email protected]d032f492009-09-29 00:33:46149 // Build command line for nacl.
[email protected]8c40f322011-08-24 03:33:36150
151#if defined(OS_MACOSX)
152 // The Native Client process needs to be able to allocate a 1GB contiguous
153 // region to use as the client environment's virtual address space. ASLR
154 // (PIE) interferes with this by making it possible that no gap large enough
155 // to accomodate this request will exist in the child process' address
156 // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
157 // http://code.google.com/p/nativeclient/issues/detail?id=2043.
158 int flags = CHILD_NO_PIE;
159#elif defined(OS_LINUX)
160 int flags = nacl_loader_prefix.empty() ? CHILD_ALLOW_SELF : CHILD_NORMAL;
161#else
162 int flags = CHILD_NORMAL;
163#endif
164
165 FilePath exe_path = GetChildPath(flags);
[email protected]fb1277e82009-11-21 20:32:30166 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46167 return false;
168
[email protected]fb1277e82009-11-21 20:32:30169 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09170 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13171
[email protected]05076ba22010-07-30 05:59:57172 cmd_line->AppendSwitchASCII(switches::kProcessType,
173 switches::kNaClLoaderProcess);
[email protected]05076ba22010-07-30 05:59:57174 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]93156cec2011-09-12 21:14:44175 if (logging::DialogsAreSuppressed())
176 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
[email protected]d032f492009-09-29 00:33:46177
[email protected]e3fc75a2011-05-05 08:20:42178 if (!nacl_loader_prefix.empty())
179 cmd_line->PrependWrapper(nacl_loader_prefix);
180
[email protected]103607e2010-02-01 18:57:09181 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46182#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09183 if (running_on_wow64_) {
[email protected]1dbaaa702011-04-06 17:43:42184 return NaClBrokerService::GetInstance()->LaunchLoader(
185 this, ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35186 } else {
[email protected]d27893f62010-07-03 05:47:42187 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35188 }
[email protected]103607e2010-02-01 18:57:09189#elif defined(OS_POSIX)
[email protected]e3fc75a2011-05-05 08:20:42190 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]d27893f62010-07-03 05:47:42191 base::environment_vector(),
192 cmd_line);
[email protected]103607e2010-02-01 18:57:09193#endif
[email protected]d032f492009-09-29 00:33:46194
[email protected]fb1277e82009-11-21 20:32:30195 return true;
[email protected]d032f492009-09-29 00:33:46196}
197
[email protected]103607e2010-02-01 18:57:09198void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
199 set_handle(handle);
200 OnProcessLaunched();
201}
202
[email protected]443b80e2010-12-14 00:42:23203base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
204 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38205 if (running_on_wow64_)
[email protected]443b80e2010-12-14 00:42:23206 return base::GetTerminationStatus(handle(), exit_code);
207 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
[email protected]103607e2010-02-01 18:57:09208}
209
[email protected]16e70ae2010-03-08 21:41:28210void NaClProcessHost::OnChildDied() {
[email protected]a0a69bf2011-09-23 21:40:28211 int exit_code;
212 GetChildTerminationStatus(&exit_code);
213 std::string message =
214 base::StringPrintf("NaCl process exited with status %i (0x%x)",
215 exit_code, exit_code);
216 if (exit_code == 0) {
217 LOG(INFO) << message;
218 } else {
219 LOG(ERROR) << message;
220 }
221
[email protected]16e70ae2010-03-08 21:41:28222#if defined(OS_WIN)
223 NaClBrokerService::GetInstance()->OnLoaderDied();
224#endif
[email protected]d27893f62010-07-03 05:47:42225 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28226}
227
[email protected]338466a82011-05-03 04:27:43228FilePath::StringType NaClProcessHost::GetIrtLibraryFilename() {
229 bool on_x86_64 = running_on_wow64_;
230#if defined(__x86_64__)
231 on_x86_64 = true;
232#endif
233 if (on_x86_64) {
234 return FILE_PATH_LITERAL("nacl_irt_x86_64.nexe");
235 } else {
236 return FILE_PATH_LITERAL("nacl_irt_x86_32.nexe");
237 }
238}
239
[email protected]fb1277e82009-11-21 20:32:30240void NaClProcessHost::OnProcessLaunched() {
[email protected]338466a82011-05-03 04:27:43241 // TODO(mseaborn): Opening the IRT file every time a NaCl process is
242 // launched probably does not work with auto-update on Linux. We
243 // might need to open the file on startup. If so, we would need to
244 // ensure that NaCl's ELF loader does not use lseek() on the shared
245 // IRT file descriptor, otherwise there would be a race condition.
[email protected]88e15832011-07-19 01:18:24246 FilePath irt_path;
247 // Allow the IRT library to be overridden via an environment
248 // variable. This allows the NaCl/Chromium integration bot to
249 // specify a newly-built IRT rather than using a prebuilt one
250 // downloaded via Chromium's DEPS file. We use the same environment
251 // variable that the standalone NaCl PPAPI plugin accepts.
252 const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
253 if (irt_path_var != NULL) {
254 FilePath::StringType string(irt_path_var,
255 irt_path_var + strlen(irt_path_var));
256 irt_path = FilePath(string);
257 } else {
258 FilePath plugin_dir;
259 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
260 LOG(ERROR) << "Failed to locate the plugins directory";
261 delete this;
262 return;
263 }
264 irt_path = plugin_dir.Append(GetIrtLibraryFilename());
[email protected]338466a82011-05-03 04:27:43265 }
[email protected]88e15832011-07-19 01:18:24266
[email protected]30c1eea2011-10-17 18:40:30267 base::FileUtilProxy::CreateOrOpenCallback callback =
268 base::Bind(&NaClProcessHost::OpenIrtFileDone, weak_factory_.GetWeakPtr());
[email protected]338466a82011-05-03 04:27:43269 if (!base::FileUtilProxy::CreateOrOpen(
270 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
271 irt_path,
272 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
273 callback)) {
[email protected]338466a82011-05-03 04:27:43274 delete this;
275 }
276}
277
278void NaClProcessHost::OpenIrtFileDone(base::PlatformFileError error_code,
279 base::PassPlatformFile file,
280 bool created) {
[email protected]c47ec402010-07-29 10:20:49281 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30282 base::ProcessHandle nacl_process_handle;
[email protected]338466a82011-05-03 04:27:43283 bool have_irt_file = false;
284 if (base::PLATFORM_FILE_OK == error_code) {
285 internal_->sockets_for_sel_ldr.push_back(file.ReleaseValue());
286 have_irt_file = true;
287 } else {
288 LOG(ERROR) << "Failed to open the NaCl IRT library file";
289 }
[email protected]fb1277e82009-11-21 20:32:30290
[email protected]1d8a3d1f2011-02-19 07:11:52291 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49292#if defined(OS_WIN)
293 // Copy the handle into the renderer process.
294 HANDLE handle_in_renderer;
[email protected]909c2402011-05-09 11:39:04295 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
296 reinterpret_cast<HANDLE>(
297 internal_->sockets_for_renderer[i]),
298 chrome_render_message_filter_->peer_handle(),
299 &handle_in_renderer,
300 0, // Unused given DUPLICATE_SAME_ACCESS.
301 FALSE,
302 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
303 LOG(ERROR) << "DuplicateHandle() failed";
304 delete this;
305 return;
306 }
[email protected]c47ec402010-07-29 10:20:49307 handles_for_renderer.push_back(
308 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
309#else
310 // No need to dup the imc_handle - we don't pass it anywhere else so
311 // it cannot be closed.
312 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52313 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49314 imc_handle.auto_close = true;
315 handles_for_renderer.push_back(imc_handle);
316#endif
317 }
318
319#if defined(OS_WIN)
320 // Copy the process handle into the renderer process.
[email protected]909c2402011-05-09 11:39:04321 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
322 handle(),
323 chrome_render_message_filter_->peer_handle(),
324 &nacl_process_handle,
325 PROCESS_DUP_HANDLE,
326 FALSE,
327 0)) {
328 LOG(ERROR) << "DuplicateHandle() failed";
329 delete this;
330 return;
331 }
[email protected]fb1277e82009-11-21 20:32:30332#else
[email protected]fb1277e82009-11-21 20:32:30333 // We use pid as process handle on Posix
334 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30335#endif
336
337 // Get the pid of the NaCl process
338 base::ProcessId nacl_process_id = base::GetProcId(handle());
339
[email protected]2ccf45c2011-08-19 23:35:50340 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49341 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]92d56412011-03-24 20:53:52342 chrome_render_message_filter_->Send(reply_msg_);
343 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30344 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52345 internal_->sockets_for_renderer.clear();
[email protected]fb1277e82009-11-21 20:32:30346
[email protected]c47ec402010-07-29 10:20:49347 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
[email protected]1d8a3d1f2011-02-19 07:11:52348 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]d032f492009-09-29 00:33:46349#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49350 HANDLE channel;
351 if (!DuplicateHandle(GetCurrentProcess(),
[email protected]1d8a3d1f2011-02-19 07:11:52352 reinterpret_cast<HANDLE>(
353 internal_->sockets_for_sel_ldr[i]),
[email protected]c47ec402010-07-29 10:20:49354 handle(),
355 &channel,
[email protected]338466a82011-05-03 04:27:43356 0, // Unused given DUPLICATE_SAME_ACCESS.
357 FALSE,
358 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
[email protected]909c2402011-05-09 11:39:04359 LOG(ERROR) << "DuplicateHandle() failed";
360 delete this;
[email protected]c47ec402010-07-29 10:20:49361 return;
362 }
363 handles_for_sel_ldr.push_back(
364 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46365#else
[email protected]c47ec402010-07-29 10:20:49366 nacl::FileDescriptor channel;
[email protected]c1d3e3b22011-07-27 02:32:11367 channel.fd = internal_->sockets_for_sel_ldr[i];
[email protected]c47ec402010-07-29 10:20:49368 channel.auto_close = true;
369 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46370#endif
[email protected]c47ec402010-07-29 10:20:49371 }
372
[email protected]2c68bf032010-11-11 23:16:30373#if defined(OS_MACOSX)
374 // For dynamic loading support, NaCl requires a file descriptor that
375 // was created in /tmp, since those created with shm_open() are not
376 // mappable with PROT_EXEC. Rather than requiring an extra IPC
377 // round trip out of the sandbox, we create an FD here.
378 base::SharedMemory memory_buffer;
379 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
380 LOG(ERROR) << "Failed to allocate memory buffer";
[email protected]909c2402011-05-09 11:39:04381 delete this;
[email protected]2c68bf032010-11-11 23:16:30382 return;
383 }
384 nacl::FileDescriptor memory_fd;
385 memory_fd.fd = dup(memory_buffer.handle().fd);
386 if (memory_fd.fd < 0) {
387 LOG(ERROR) << "Failed to dup() a file descriptor";
[email protected]909c2402011-05-09 11:39:04388 delete this;
[email protected]2c68bf032010-11-11 23:16:30389 return;
390 }
391 memory_fd.auto_close = true;
392 handles_for_sel_ldr.push_back(memory_fd);
393#endif
394
[email protected]338466a82011-05-03 04:27:43395 Send(new NaClProcessMsg_Start(handles_for_sel_ldr, have_irt_file));
[email protected]1d8a3d1f2011-02-19 07:11:52396 internal_->sockets_for_sel_ldr.clear();
[email protected]d032f492009-09-29 00:33:46397}
398
[email protected]a95986a82010-12-24 06:19:28399bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
[email protected]d032f492009-09-29 00:33:46400 NOTREACHED() << "Invalid message with type = " << msg.type();
[email protected]a95986a82010-12-24 06:19:28401 return false;
[email protected]d032f492009-09-29 00:33:46402}
403
[email protected]e4be2dd2010-12-14 00:44:39404bool NaClProcessHost::CanShutdown() {
405 return true;
406}