blob: 528e38091efc808abc6eb959c9e14fa996833554 [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]92d56412011-03-24 20:53:5222#include "chrome/browser/renderer_host/chrome_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]1dbaaa702011-04-06 17:43:4252NaClProcessHost::NaClProcessHost(const std::wstring& url)
53 : BrowserChildProcessHost(NACL_LOADER_PROCESS, NULL),
[email protected]fb1277e82009-11-21 20:32:3054 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:5255 internal_(new NaClInternal()),
[email protected]103607e2010-02-01 18:57:0956 running_on_wow64_(false) {
[email protected]f08e47d2009-10-15 21:46:1557 set_name(url);
[email protected]103607e2010-02-01 18:57:0958#if defined(OS_WIN)
[email protected]1e67c2b2011-03-04 01:17:3759 running_on_wow64_ = (base::win::GetWOW64Status() == base::win::WOW64_ENABLED);
[email protected]103607e2010-02-01 18:57:0960#endif
[email protected]d032f492009-09-29 00:33:4661}
62
[email protected]fb1277e82009-11-21 20:32:3063NaClProcessHost::~NaClProcessHost() {
64 if (!reply_msg_)
65 return;
66
[email protected]990b29e2010-07-29 12:53:4767 // nacl::Close() is not available at link time if DISABLE_NACL is
68 // defined, but we still compile a bunch of other code from this
69 // file anyway. TODO(mseaborn): Make this less messy.
70#ifndef DISABLE_NACL
[email protected]1d8a3d1f2011-02-19 07:11:5271 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
72 nacl::Close(internal_->sockets_for_renderer[i]);
[email protected]c47ec402010-07-29 10:20:4973 }
[email protected]1d8a3d1f2011-02-19 07:11:5274 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
75 nacl::Close(internal_->sockets_for_sel_ldr[i]);
[email protected]c47ec402010-07-29 10:20:4976 }
[email protected]990b29e2010-07-29 12:53:4777#endif
[email protected]c47ec402010-07-29 10:20:4978
[email protected]fb1277e82009-11-21 20:32:3079 // OnProcessLaunched didn't get called because the process couldn't launch.
80 // Don't keep the renderer hanging.
81 reply_msg_->set_reply_error();
[email protected]92d56412011-03-24 20:53:5282 chrome_render_message_filter_->Send(reply_msg_);
[email protected]fb1277e82009-11-21 20:32:3083}
84
[email protected]92d56412011-03-24 20:53:5285bool NaClProcessHost::Launch(
86 ChromeRenderMessageFilter* chrome_render_message_filter,
87 int socket_count,
88 IPC::Message* reply_msg) {
[email protected]d8c7cbcc2009-10-02 19:00:3189#ifdef DISABLE_NACL
90 NOTIMPLEMENTED() << "Native Client disabled at build time";
91 return false;
92#else
[email protected]c47ec402010-07-29 10:20:4993 // Place an arbitrary limit on the number of sockets to limit
94 // exposure in case the renderer is compromised. We can increase
95 // this if necessary.
96 if (socket_count > 8) {
[email protected]d032f492009-09-29 00:33:4697 return false;
[email protected]c47ec402010-07-29 10:20:4998 }
99
100 // Rather than creating a socket pair in the renderer, and passing
101 // one side through the browser to sel_ldr, socket pairs are created
102 // in the browser and then passed to the renderer and sel_ldr.
103 //
104 // This is mainly for the benefit of Windows, where sockets cannot
105 // be passed in messages, but are copied via DuplicateHandle().
106 // This means the sandboxed renderer cannot send handles to the
107 // browser process.
108
109 for (int i = 0; i < socket_count; i++) {
110 nacl::Handle pair[2];
111 // Create a connected socket
112 if (nacl::SocketPair(pair) == -1)
113 return false;
[email protected]1d8a3d1f2011-02-19 07:11:52114 internal_->sockets_for_renderer.push_back(pair[0]);
115 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49116 SetCloseOnExec(pair[0]);
117 SetCloseOnExec(pair[1]);
118 }
[email protected]d032f492009-09-29 00:33:46119
120 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30121 if (!LaunchSelLdr()) {
[email protected]d032f492009-09-29 00:33:46122 return false;
123 }
[email protected]9ec74462010-10-28 16:48:05124 UmaNaclHistogramEnumeration(NACL_STARTED);
[email protected]92d56412011-03-24 20:53:52125 chrome_render_message_filter_ = chrome_render_message_filter;
[email protected]fb1277e82009-11-21 20:32:30126 reply_msg_ = reply_msg;
[email protected]f08e47d2009-10-15 21:46:15127
[email protected]d032f492009-09-29 00:33:46128 return true;
[email protected]d8c7cbcc2009-10-02 19:00:31129#endif // DISABLE_NACL
[email protected]d032f492009-09-29 00:33:46130}
131
[email protected]fb1277e82009-11-21 20:32:30132bool NaClProcessHost::LaunchSelLdr() {
[email protected]d032f492009-09-29 00:33:46133 if (!CreateChannel())
134 return false;
135
136 // Build command line for nacl.
[email protected]7c4ea142010-01-26 05:15:42137 FilePath exe_path = GetChildPath(true);
[email protected]fb1277e82009-11-21 20:32:30138 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46139 return false;
140
[email protected]fb1277e82009-11-21 20:32:30141 CommandLine* cmd_line = new CommandLine(exe_path);
[email protected]103607e2010-02-01 18:57:09142 nacl::CopyNaClCommandLineArguments(cmd_line);
[email protected]599e6642010-01-27 18:52:13143
[email protected]05076ba22010-07-30 05:59:57144 cmd_line->AppendSwitchASCII(switches::kProcessType,
145 switches::kNaClLoaderProcess);
[email protected]d032f492009-09-29 00:33:46146
[email protected]05076ba22010-07-30 05:59:57147 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id());
[email protected]d032f492009-09-29 00:33:46148
[email protected]67842522011-01-14 18:27:37149 SetCrashReporterCommandLine(cmd_line);
150
[email protected]103607e2010-02-01 18:57:09151 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46152#if defined(OS_WIN)
[email protected]103607e2010-02-01 18:57:09153 if (running_on_wow64_) {
[email protected]1dbaaa702011-04-06 17:43:42154 return NaClBrokerService::GetInstance()->LaunchLoader(
155 this, ASCIIToWide(channel_id()));
[email protected]4bdde602010-06-16 03:17:35156 } else {
[email protected]d27893f62010-07-03 05:47:42157 BrowserChildProcessHost::Launch(FilePath(), cmd_line);
[email protected]4bdde602010-06-16 03:17:35158 }
[email protected]103607e2010-02-01 18:57:09159#elif defined(OS_POSIX)
[email protected]d27893f62010-07-03 05:47:42160 BrowserChildProcessHost::Launch(true, // use_zygote
161 base::environment_vector(),
162 cmd_line);
[email protected]103607e2010-02-01 18:57:09163#endif
[email protected]d032f492009-09-29 00:33:46164
[email protected]fb1277e82009-11-21 20:32:30165 return true;
[email protected]d032f492009-09-29 00:33:46166}
167
[email protected]103607e2010-02-01 18:57:09168void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
169 set_handle(handle);
170 OnProcessLaunched();
171}
172
[email protected]443b80e2010-12-14 00:42:23173base::TerminationStatus NaClProcessHost::GetChildTerminationStatus(
174 int* exit_code) {
[email protected]cd69619b2010-05-05 02:41:38175 if (running_on_wow64_)
[email protected]443b80e2010-12-14 00:42:23176 return base::GetTerminationStatus(handle(), exit_code);
177 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code);
[email protected]103607e2010-02-01 18:57:09178}
179
[email protected]16e70ae2010-03-08 21:41:28180void NaClProcessHost::OnChildDied() {
181#if defined(OS_WIN)
182 NaClBrokerService::GetInstance()->OnLoaderDied();
183#endif
[email protected]d27893f62010-07-03 05:47:42184 BrowserChildProcessHost::OnChildDied();
[email protected]16e70ae2010-03-08 21:41:28185}
186
[email protected]fb1277e82009-11-21 20:32:30187void NaClProcessHost::OnProcessLaunched() {
[email protected]c47ec402010-07-29 10:20:49188 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]fb1277e82009-11-21 20:32:30189 base::ProcessHandle nacl_process_handle;
[email protected]fb1277e82009-11-21 20:32:30190
[email protected]1d8a3d1f2011-02-19 07:11:52191 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49192#if defined(OS_WIN)
193 // Copy the handle into the renderer process.
194 HANDLE handle_in_renderer;
195 DuplicateHandle(base::GetCurrentProcessHandle(),
[email protected]1d8a3d1f2011-02-19 07:11:52196 reinterpret_cast<HANDLE>(
197 internal_->sockets_for_renderer[i]),
[email protected]92d56412011-03-24 20:53:52198 chrome_render_message_filter_->peer_handle(),
[email protected]c47ec402010-07-29 10:20:49199 &handle_in_renderer,
200 GENERIC_READ | GENERIC_WRITE,
201 FALSE,
202 DUPLICATE_CLOSE_SOURCE);
203 handles_for_renderer.push_back(
204 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
205#else
206 // No need to dup the imc_handle - we don't pass it anywhere else so
207 // it cannot be closed.
208 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52209 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49210 imc_handle.auto_close = true;
211 handles_for_renderer.push_back(imc_handle);
212#endif
213 }
214
215#if defined(OS_WIN)
216 // Copy the process handle into the renderer process.
[email protected]fb1277e82009-11-21 20:32:30217 DuplicateHandle(base::GetCurrentProcessHandle(),
218 handle(),
[email protected]92d56412011-03-24 20:53:52219 chrome_render_message_filter_->peer_handle(),
[email protected]fb1277e82009-11-21 20:32:30220 &nacl_process_handle,
221 PROCESS_DUP_HANDLE,
222 FALSE,
223 0);
[email protected]fb1277e82009-11-21 20:32:30224#else
[email protected]fb1277e82009-11-21 20:32:30225 // We use pid as process handle on Posix
226 nacl_process_handle = handle();
[email protected]fb1277e82009-11-21 20:32:30227#endif
228
229 // Get the pid of the NaCl process
230 base::ProcessId nacl_process_id = base::GetProcId(handle());
231
232 ViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]c47ec402010-07-29 10:20:49233 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id);
[email protected]92d56412011-03-24 20:53:52234 chrome_render_message_filter_->Send(reply_msg_);
235 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30236 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52237 internal_->sockets_for_renderer.clear();
[email protected]fb1277e82009-11-21 20:32:30238
239 SendStartMessage();
240}
241
242void NaClProcessHost::SendStartMessage() {
[email protected]c47ec402010-07-29 10:20:49243 std::vector<nacl::FileDescriptor> handles_for_sel_ldr;
[email protected]1d8a3d1f2011-02-19 07:11:52244 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]d032f492009-09-29 00:33:46245#if defined(OS_WIN)
[email protected]c47ec402010-07-29 10:20:49246 HANDLE channel;
247 if (!DuplicateHandle(GetCurrentProcess(),
[email protected]1d8a3d1f2011-02-19 07:11:52248 reinterpret_cast<HANDLE>(
249 internal_->sockets_for_sel_ldr[i]),
[email protected]c47ec402010-07-29 10:20:49250 handle(),
251 &channel,
252 GENERIC_READ | GENERIC_WRITE,
253 FALSE, DUPLICATE_CLOSE_SOURCE)) {
254 return;
255 }
256 handles_for_sel_ldr.push_back(
257 reinterpret_cast<nacl::FileDescriptor>(channel));
[email protected]d032f492009-09-29 00:33:46258#else
[email protected]c47ec402010-07-29 10:20:49259 nacl::FileDescriptor channel;
[email protected]1d8a3d1f2011-02-19 07:11:52260 channel.fd = dup(internal_->sockets_for_sel_ldr[i]);
[email protected]2c68bf032010-11-11 23:16:30261 if (channel.fd < 0) {
262 LOG(ERROR) << "Failed to dup() a file descriptor";
263 return;
264 }
[email protected]c47ec402010-07-29 10:20:49265 channel.auto_close = true;
266 handles_for_sel_ldr.push_back(channel);
[email protected]d032f492009-09-29 00:33:46267#endif
[email protected]c47ec402010-07-29 10:20:49268 }
269
[email protected]2c68bf032010-11-11 23:16:30270#if defined(OS_MACOSX)
271 // For dynamic loading support, NaCl requires a file descriptor that
272 // was created in /tmp, since those created with shm_open() are not
273 // mappable with PROT_EXEC. Rather than requiring an extra IPC
274 // round trip out of the sandbox, we create an FD here.
275 base::SharedMemory memory_buffer;
276 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) {
277 LOG(ERROR) << "Failed to allocate memory buffer";
278 return;
279 }
280 nacl::FileDescriptor memory_fd;
281 memory_fd.fd = dup(memory_buffer.handle().fd);
282 if (memory_fd.fd < 0) {
283 LOG(ERROR) << "Failed to dup() a file descriptor";
284 return;
285 }
286 memory_fd.auto_close = true;
287 handles_for_sel_ldr.push_back(memory_fd);
288#endif
289
[email protected]c47ec402010-07-29 10:20:49290 Send(new NaClProcessMsg_Start(handles_for_sel_ldr));
[email protected]1d8a3d1f2011-02-19 07:11:52291 internal_->sockets_for_sel_ldr.clear();
[email protected]d032f492009-09-29 00:33:46292}
293
[email protected]a95986a82010-12-24 06:19:28294bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
[email protected]d032f492009-09-29 00:33:46295 NOTREACHED() << "Invalid message with type = " << msg.type();
[email protected]a95986a82010-12-24 06:19:28296 return false;
[email protected]d032f492009-09-29 00:33:46297}
298
[email protected]e4be2dd2010-12-14 00:44:39299bool NaClProcessHost::CanShutdown() {
300 return true;
301}