blob: c8eb47afab339378d89308faa0ecb429228370b9 [file] [log] [blame]
[email protected]b39c6d92012-01-31 16:38:411// Copyright (c) 2012 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
[email protected]e15a4fa2010-02-11 23:09:295#include "chrome/browser/nacl_host/nacl_process_host.h"
[email protected]d032f492009-09-29 00:33:466
[email protected]a82af392012-02-24 04:40:207#include <string>
8#include <vector>
[email protected]d032f492009-09-29 00:33:469
[email protected]30c1eea2011-10-17 18:40:3010#include "base/bind.h"
[email protected]103607e2010-02-01 18:57:0911#include "base/command_line.h"
[email protected]5b974952012-04-05 18:18:2312#include "base/message_loop.h"
[email protected]9addd1c2012-09-15 14:28:2413#include "base/metrics/histogram.h"
[email protected]338466a82011-05-03 04:27:4314#include "base/path_service.h"
[email protected]108fd342013-01-04 20:46:5415#include "base/process_util.h"
[email protected]5b974952012-04-05 18:18:2316#include "base/string_number_conversions.h"
17#include "base/string_split.h"
[email protected]8f42b4d2012-03-24 14:12:3318#include "base/string_util.h"
[email protected]a0a69bf2011-09-23 21:40:2819#include "base/stringprintf.h"
[email protected]be1ce6a72010-08-03 14:35:2220#include "base/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3721#include "base/win/windows_version.h"
[email protected]a82af392012-02-24 04:40:2022#include "build/build_config.h"
[email protected]8510d282012-08-30 19:47:3823#include "chrome/browser/browser_process.h"
[email protected]8f42b4d2012-03-24 14:12:3324#include "chrome/browser/extensions/extension_info_map.h"
[email protected]8510d282012-08-30 19:47:3825#include "chrome/browser/io_thread.h"
[email protected]2e5f2ea42012-05-09 21:39:2126#include "chrome/browser/nacl_host/nacl_browser.h"
[email protected]8f42b4d2012-03-24 14:12:3327#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]31a665e72012-03-11 12:37:4628#include "chrome/common/chrome_constants.h"
[email protected]338466a82011-05-03 04:27:4329#include "chrome/common/chrome_paths.h"
[email protected]d032f492009-09-29 00:33:4630#include "chrome/common/chrome_switches.h"
[email protected]1657e6d2012-03-30 20:28:0031#include "chrome/common/chrome_version_info.h"
[email protected]d032f492009-09-29 00:33:4632#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0933#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4634#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3035#include "chrome/common/render_messages.h"
[email protected]8f42b4d2012-03-24 14:12:3336#include "chrome/common/url_constants.h"
[email protected]4967f792012-01-20 22:14:4037#include "content/public/browser/browser_child_process_host.h"
[email protected]0c7193742012-11-07 19:05:0338#include "content/public/browser/browser_ppapi_host.h"
[email protected]4967f792012-01-20 22:14:4039#include "content/public/browser/child_process_data.h"
[email protected]4734d0b2011-12-03 07:10:4440#include "content/public/common/child_process_host.h"
[email protected]885c0e92012-11-13 20:27:4241#include "extensions/common/constants.h"
42#include "extensions/common/url_pattern.h"
[email protected]8510d282012-08-30 19:47:3843#include "ipc/ipc_channel.h"
[email protected]d032f492009-09-29 00:33:4644#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5245#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]87f35592012-04-08 00:49:1646#include "net/base/net_util.h"
[email protected]d571c032012-09-14 12:39:1847#include "net/base/tcp_listen_socket.h"
[email protected]8510d282012-08-30 19:47:3848#include "ppapi/proxy/ppapi_messages.h"
[email protected]d032f492009-09-29 00:33:4649
[email protected]d032f492009-09-29 00:33:4650#if defined(OS_POSIX)
[email protected]a82af392012-02-24 04:40:2051#include <fcntl.h>
52
[email protected]d032f492009-09-29 00:33:4653#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3554#elif defined(OS_WIN)
[email protected]a82af392012-02-24 04:40:2055#include <windows.h>
56
[email protected]b39c6d92012-01-31 16:38:4157#include "base/process_util.h"
[email protected]885c0e92012-11-13 20:27:4258#include "base/threading/thread.h"
[email protected]4c65fb632012-04-27 00:42:2559#include "base/win/scoped_handle.h"
[email protected]4bdde602010-06-16 03:17:3560#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]ea6588842012-05-03 05:39:3861#include "chrome/common/nacl_debug_exception_handler_win.h"
[email protected]e4f6eb0232012-04-17 00:47:5062#include "content/public/common/sandbox_init.h"
[email protected]d032f492009-09-29 00:33:4663#endif
64
[email protected]631bb742011-11-02 11:29:3965using content::BrowserThread;
[email protected]4967f792012-01-20 22:14:4066using content::ChildProcessData;
[email protected]4734d0b2011-12-03 07:10:4467using content::ChildProcessHost;
[email protected]8510d282012-08-30 19:47:3868using ppapi::proxy::SerializedHandle;
[email protected]631bb742011-11-02 11:29:3969
[email protected]646e15552012-04-06 22:01:0470namespace {
71
72#if defined(OS_WIN)
73bool RunningOnWOW64() {
74 return (base::win::OSInfo::GetInstance()->wow64_status() ==
75 base::win::OSInfo::WOW64_ENABLED);
76}
77#endif
78
[email protected]646e15552012-04-06 22:01:0479void SetCloseOnExec(nacl::Handle fd) {
80#if defined(OS_POSIX)
81 int flags = fcntl(fd, F_GETFD);
82 CHECK_NE(flags, -1);
83 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
84 CHECK_EQ(rc, 0);
85#endif
86}
87
[email protected]00d99542012-04-17 22:48:0288bool ShareHandleToSelLdr(
[email protected]646e15552012-04-06 22:01:0489 base::ProcessHandle processh,
90 nacl::Handle sourceh,
91 bool close_source,
92 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
93#if defined(OS_WIN)
94 HANDLE channel;
95 int flags = DUPLICATE_SAME_ACCESS;
96 if (close_source)
97 flags |= DUPLICATE_CLOSE_SOURCE;
98 if (!DuplicateHandle(GetCurrentProcess(),
99 reinterpret_cast<HANDLE>(sourceh),
100 processh,
101 &channel,
102 0, // Unused given DUPLICATE_SAME_ACCESS.
103 FALSE,
104 flags)) {
[email protected]09afc2e2012-04-10 17:29:03105 DLOG(ERROR) << "DuplicateHandle() failed";
[email protected]646e15552012-04-06 22:01:04106 return false;
107 }
108 handles_for_sel_ldr->push_back(
109 reinterpret_cast<nacl::FileDescriptor>(channel));
110#else
111 nacl::FileDescriptor channel;
112 channel.fd = sourceh;
113 channel.auto_close = close_source;
114 handles_for_sel_ldr->push_back(channel);
115#endif
116 return true;
117}
118
[email protected]27b04df2012-12-10 23:43:10119ppapi::PpapiPermissions GetNaClPermissions(uint32 permission_bits) {
120 // Only allow NaCl plugins to request certain permissions. We don't want
121 // a compromised renderer to be able to start a nacl plugin with e.g. Flash
122 // permissions which may expand the surface area of the sandbox.
123 uint32 masked_bits = permission_bits & ppapi::PERMISSION_DEV;
124 return ppapi::PpapiPermissions::GetForCommandLine(masked_bits);
125}
126
[email protected]646e15552012-04-06 22:01:04127} // namespace
128
[email protected]1d8a3d1f2011-02-19 07:11:52129struct NaClProcessHost::NaClInternal {
[email protected]6294dd02013-01-09 17:27:23130 nacl::Handle socket_for_renderer;
131 nacl::Handle socket_for_sel_ldr;
132
133 NaClInternal()
134 : socket_for_renderer(nacl::kInvalidHandle),
135 socket_for_sel_ldr(nacl::kInvalidHandle) { }
[email protected]1d8a3d1f2011-02-19 07:11:52136};
137
[email protected]646e15552012-04-06 22:01:04138// -----------------------------------------------------------------------------
[email protected]773ebb92011-11-15 19:06:52139
[email protected]8510d282012-08-30 19:47:38140NaClProcessHost::PluginListener::PluginListener(NaClProcessHost* host)
141 : host_(host) {
142}
143
144bool NaClProcessHost::PluginListener::OnMessageReceived(
145 const IPC::Message& msg) {
146 return host_->OnUntrustedMessageForwarded(msg);
147}
148
[email protected]9da4fed2012-11-01 17:07:55149NaClProcessHost::NaClProcessHost(const GURL& manifest_url,
[email protected]e02ff722012-11-06 03:53:06150 int render_view_id,
[email protected]9da4fed2012-11-01 17:07:55151 uint32 permission_bits,
152 bool off_the_record)
[email protected]87f35592012-04-08 00:49:16153 : manifest_url_(manifest_url),
[email protected]27b04df2012-12-10 23:43:10154 permissions_(GetNaClPermissions(permission_bits)),
[email protected]a575da52012-03-22 13:08:36155#if defined(OS_WIN)
156 process_launched_by_broker_(false),
[email protected]5b974952012-04-05 18:18:23157#elif defined(OS_LINUX)
158 wait_for_nacl_gdb_(false),
[email protected]a575da52012-03-22 13:08:36159#endif
160 reply_msg_(NULL),
[email protected]ea6588842012-05-03 05:39:38161#if defined(OS_WIN)
162 debug_exception_handler_requested_(false),
163#endif
[email protected]1d8a3d1f2011-02-19 07:11:52164 internal_(new NaClInternal()),
[email protected]5ca93be2012-03-21 20:04:06165 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
[email protected]57473ebc2012-05-30 07:44:52166 enable_exception_handling_(false),
[email protected]2c227ff2012-08-11 00:51:32167 enable_debug_stub_(false),
[email protected]8510d282012-08-30 19:47:38168 off_the_record_(off_the_record),
169 enable_ipc_proxy_(false),
[email protected]e02ff722012-11-06 03:53:06170 ALLOW_THIS_IN_INITIALIZER_LIST(ipc_plugin_listener_(this)),
171 render_view_id_(render_view_id) {
[email protected]4967f792012-01-20 22:14:40172 process_.reset(content::BrowserChildProcessHost::Create(
173 content::PROCESS_TYPE_NACL_LOADER, this));
[email protected]87f35592012-04-08 00:49:16174
175 // Set the display name so the user knows what plugin the process is running.
176 // We aren't on the UI thread so getting the pref locale for language
177 // formatting isn't possible, so IDN will be lost, but this is probably OK
178 // for this use case.
179 process_->SetName(net::FormatUrl(manifest_url_, std::string()));
[email protected]5ca93be2012-03-21 20:04:06180
181 // We allow untrusted hardware exception handling to be enabled via
182 // an env var for consistency with the standalone build of NaCl.
183 if (CommandLine::ForCurrentProcess()->HasSwitch(
184 switches::kEnableNaClExceptionHandling) ||
185 getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
186 enable_exception_handling_ = true;
[email protected]5ca93be2012-03-21 20:04:06187 }
[email protected]2c227ff2012-08-11 00:51:32188 enable_debug_stub_ = CommandLine::ForCurrentProcess()->HasSwitch(
189 switches::kEnableNaClDebug);
[email protected]17b5a8172012-06-22 21:09:09190
[email protected]45a9c0a2012-11-08 21:00:29191 enable_ipc_proxy_ = !CommandLine::ForCurrentProcess()->HasSwitch(
192 switches::kEnableNaClSRPCProxy);
[email protected]778a40252012-12-04 19:20:44193 // If render_view_id == 0 we do not need PPAPI, so we can skip
194 // PPAPI IPC proxy channel creation, etc.
195 if (!render_view_id_)
196 enable_ipc_proxy_ = false;
[email protected]d032f492009-09-29 00:33:46197}
198
[email protected]fb1277e82009-11-21 20:32:30199NaClProcessHost::~NaClProcessHost() {
[email protected]4cb43102011-12-02 20:24:49200 int exit_code;
[email protected]4967f792012-01-20 22:14:40201 process_->GetTerminationStatus(&exit_code);
[email protected]4cb43102011-12-02 20:24:49202 std::string message =
203 base::StringPrintf("NaCl process exited with status %i (0x%x)",
204 exit_code, exit_code);
205 if (exit_code == 0) {
206 LOG(INFO) << message;
207 } else {
208 LOG(ERROR) << message;
209 }
210
[email protected]6294dd02013-01-09 17:27:23211 if (internal_->socket_for_renderer != nacl::kInvalidHandle) {
212 if (nacl::Close(internal_->socket_for_renderer) != 0) {
[email protected]09afc2e2012-04-10 17:29:03213 NOTREACHED() << "nacl::Close() failed";
[email protected]909c2402011-05-09 11:39:04214 }
[email protected]c47ec402010-07-29 10:20:49215 }
[email protected]6294dd02013-01-09 17:27:23216
217 if (internal_->socket_for_sel_ldr != nacl::kInvalidHandle) {
218 if (nacl::Close(internal_->socket_for_sel_ldr) != 0) {
[email protected]09afc2e2012-04-10 17:29:03219 NOTREACHED() << "nacl::Close() failed";
[email protected]909c2402011-05-09 11:39:04220 }
[email protected]c47ec402010-07-29 10:20:49221 }
222
[email protected]909c2402011-05-09 11:39:04223 if (reply_msg_) {
224 // The process failed to launch for some reason.
225 // Don't keep the renderer hanging.
226 reply_msg_->set_reply_error();
227 chrome_render_message_filter_->Send(reply_msg_);
228 }
[email protected]b39c6d92012-01-31 16:38:41229#if defined(OS_WIN)
[email protected]a575da52012-03-22 13:08:36230 if (process_launched_by_broker_) {
231 NaClBrokerService::GetInstance()->OnLoaderDied();
[email protected]5ca93be2012-03-21 20:04:06232 }
[email protected]b39c6d92012-01-31 16:38:41233#endif
[email protected]fb1277e82009-11-21 20:32:30234}
235
[email protected]773ebb92011-11-15 19:06:52236// This is called at browser startup.
237// static
238void NaClProcessHost::EarlyStartup() {
239#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
240 // Open the IRT file early to make sure that it isn't replaced out from
241 // under us by autoupdate.
242 NaClBrowser::GetInstance()->EnsureIrtAvailable();
243#endif
[email protected]9addd1c2012-09-15 14:28:24244 CommandLine* cmd = CommandLine::ForCurrentProcess();
245 UMA_HISTOGRAM_BOOLEAN(
246 "NaCl.nacl-gdb",
247 !cmd->GetSwitchValuePath(switches::kNaClGdb).empty());
248 UMA_HISTOGRAM_BOOLEAN(
249 "NaCl.nacl-gdb-script",
250 !cmd->GetSwitchValuePath(switches::kNaClGdbScript).empty());
251 UMA_HISTOGRAM_BOOLEAN(
252 "NaCl.enable-nacl-debug",
253 cmd->HasSwitch(switches::kEnableNaClDebug));
[email protected]66f409c2012-10-04 20:59:04254 NaClBrowser::GetInstance()->SetDebugPatterns(
255 cmd->GetSwitchValueASCII(switches::kNaClDebugMask));
[email protected]773ebb92011-11-15 19:06:52256}
257
[email protected]a575da52012-03-22 13:08:36258void NaClProcessHost::Launch(
[email protected]92d56412011-03-24 20:53:52259 ChromeRenderMessageFilter* chrome_render_message_filter,
[email protected]8f42b4d2012-03-24 14:12:33260 IPC::Message* reply_msg,
261 scoped_refptr<ExtensionInfoMap> extension_info_map) {
[email protected]a575da52012-03-22 13:08:36262 chrome_render_message_filter_ = chrome_render_message_filter;
263 reply_msg_ = reply_msg;
[email protected]8f42b4d2012-03-24 14:12:33264 extension_info_map_ = extension_info_map;
[email protected]a575da52012-03-22 13:08:36265
[email protected]773ebb92011-11-15 19:06:52266 // Start getting the IRT open asynchronously while we launch the NaCl process.
[email protected]09afc2e2012-04-10 17:29:03267 // We'll make sure this actually finished in StartWithLaunchedProcess, below.
[email protected]e97990f2012-05-15 22:06:06268 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
269 nacl_browser->EnsureAllResourcesAvailable();
270 if (!nacl_browser->IsOk()) {
271 DLOG(ERROR) << "Cannot launch NaCl process";
[email protected]a575da52012-03-22 13:08:36272 delete this;
273 return;
[email protected]773ebb92011-11-15 19:06:52274 }
275
[email protected]c47ec402010-07-29 10:20:49276 // Rather than creating a socket pair in the renderer, and passing
277 // one side through the browser to sel_ldr, socket pairs are created
278 // in the browser and then passed to the renderer and sel_ldr.
279 //
280 // This is mainly for the benefit of Windows, where sockets cannot
281 // be passed in messages, but are copied via DuplicateHandle().
282 // This means the sandboxed renderer cannot send handles to the
283 // browser process.
284
[email protected]6294dd02013-01-09 17:27:23285 nacl::Handle pair[2];
286 // Create a connected socket
287 if (nacl::SocketPair(pair) == -1) {
288 delete this;
289 return;
[email protected]c47ec402010-07-29 10:20:49290 }
[email protected]6294dd02013-01-09 17:27:23291 internal_->socket_for_renderer = pair[0];
292 internal_->socket_for_sel_ldr = pair[1];
293 SetCloseOnExec(pair[0]);
294 SetCloseOnExec(pair[1]);
[email protected]d032f492009-09-29 00:33:46295
296 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30297 if (!LaunchSelLdr()) {
[email protected]a575da52012-03-22 13:08:36298 delete this;
[email protected]d032f492009-09-29 00:33:46299 }
[email protected]d032f492009-09-29 00:33:46300}
[email protected]646e15552012-04-06 22:01:04301
[email protected]5b974952012-04-05 18:18:23302#if defined(OS_WIN)
[email protected]646e15552012-04-06 22:01:04303void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
304 // Set process handle, if it was not set previously.
305 // This is needed when NaCl process is launched with nacl-gdb.
[email protected]82d17502012-05-23 19:12:40306 if (!CommandLine::ForCurrentProcess()->GetSwitchValuePath(
307 switches::kNaClGdb).empty()) {
[email protected]646e15552012-04-06 22:01:04308 base::ProcessHandle process;
[email protected]82d17502012-05-23 19:12:40309 DCHECK(process_->GetData().handle == base::kNullProcessHandle);
[email protected]646e15552012-04-06 22:01:04310 if (base::OpenProcessHandleWithAccess(
311 peer_pid,
312 base::kProcessAccessDuplicateHandle |
313 base::kProcessAccessQueryInformation |
314 base::kProcessAccessWaitForTermination,
315 &process)) {
316 process_->SetHandle(process);
[email protected]09afc2e2012-04-10 17:29:03317 if (!StartWithLaunchedProcess()) {
318 delete this;
319 return;
320 }
[email protected]646e15552012-04-06 22:01:04321 } else {
[email protected]09afc2e2012-04-10 17:29:03322 DLOG(ERROR) << "Failed to get process handle";
[email protected]646e15552012-04-06 22:01:04323 }
324 }
[email protected]646e15552012-04-06 22:01:04325}
326#else
327void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
328}
329#endif
330
331#if defined(OS_WIN)
332void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
333 process_launched_by_broker_ = true;
334 process_->SetHandle(handle);
[email protected]09afc2e2012-04-10 17:29:03335 if (!StartWithLaunchedProcess())
336 delete this;
[email protected]646e15552012-04-06 22:01:04337}
338
[email protected]ea6588842012-05-03 05:39:38339void NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker(bool success) {
340 IPC::Message* reply = attach_debug_exception_handler_reply_msg_.release();
341 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply, success);
342 Send(reply);
[email protected]646e15552012-04-06 22:01:04343}
344#endif
345
346// Needed to handle sync messages in OnMessageRecieved.
347bool NaClProcessHost::Send(IPC::Message* msg) {
348 return process_->Send(msg);
349}
350
351#if defined(OS_WIN)
352scoped_ptr<CommandLine> NaClProcessHost::GetCommandForLaunchWithGdb(
[email protected]8f42b4d2012-03-24 14:12:33353 const FilePath& nacl_gdb,
[email protected]5b974952012-04-05 18:18:23354 CommandLine* line) {
[email protected]31a665e72012-03-11 12:37:46355 CommandLine* cmd_line = new CommandLine(nacl_gdb);
356 // We can't use PrependWrapper because our parameters contain spaces.
357 cmd_line->AppendArg("--eval-command");
358 const FilePath::StringType& irt_path =
359 NaClBrowser::GetInstance()->GetIrtFilePath().value();
360 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
[email protected]5b974952012-04-05 18:18:23361 FilePath manifest_path = GetManifestPath();
[email protected]8f42b4d2012-03-24 14:12:33362 if (!manifest_path.empty()) {
363 cmd_line->AppendArg("--eval-command");
364 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
365 manifest_path.value());
366 }
[email protected]401b90792012-05-30 11:41:13367 FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
368 switches::kNaClGdbScript);
369 if (!script.empty()) {
370 cmd_line->AppendArg("--command");
371 cmd_line->AppendArgNative(script.value());
372 }
[email protected]31a665e72012-03-11 12:37:46373 cmd_line->AppendArg("--args");
374 const CommandLine::StringVector& argv = line->argv();
375 for (size_t i = 0; i < argv.size(); i++) {
376 cmd_line->AppendArgNative(argv[i]);
377 }
378 return scoped_ptr<CommandLine>(cmd_line);
379}
[email protected]5b974952012-04-05 18:18:23380#elif defined(OS_LINUX)
[email protected]512d03f2012-06-26 01:06:06381class NaClProcessHost::NaClGdbWatchDelegate
382 : public MessageLoopForIO::Watcher {
[email protected]5b974952012-04-05 18:18:23383 public:
384 // fd_write_ is used by nacl-gdb via /proc/browser_PID/fd/fd_write_
385 NaClGdbWatchDelegate(int fd_read, int fd_write,
386 const base::Closure& reply)
387 : fd_read_(fd_read),
388 fd_write_(fd_write),
389 reply_(reply) {}
390
391 ~NaClGdbWatchDelegate() {
392 if (HANDLE_EINTR(close(fd_read_)) != 0)
393 DLOG(ERROR) << "close(fd_read_) failed";
394 if (HANDLE_EINTR(close(fd_write_)) != 0)
395 DLOG(ERROR) << "close(fd_write_) failed";
396 }
397
398 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
399 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
400
401 private:
402 int fd_read_;
403 int fd_write_;
404 base::Closure reply_;
405};
406
[email protected]512d03f2012-06-26 01:06:06407void NaClProcessHost::NaClGdbWatchDelegate::OnFileCanReadWithoutBlocking(
408 int fd) {
[email protected]5b974952012-04-05 18:18:23409 char buf;
410 if (HANDLE_EINTR(read(fd_read_, &buf, 1)) != 1 || buf != '\0')
411 LOG(ERROR) << "Failed to sync with nacl-gdb";
412 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, reply_);
413}
[email protected]5b974952012-04-05 18:18:23414
415bool NaClProcessHost::LaunchNaClGdb(base::ProcessId pid) {
416 CommandLine::StringType nacl_gdb =
417 CommandLine::ForCurrentProcess()->GetSwitchValueNative(
418 switches::kNaClGdb);
419 CommandLine::StringVector argv;
420 // We don't support spaces inside arguments in --nacl-gdb switch.
421 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
422 CommandLine cmd_line(argv);
423 cmd_line.AppendArg("--eval-command");
424 const FilePath::StringType& irt_path =
425 NaClBrowser::GetInstance()->GetIrtFilePath().value();
426 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
427 FilePath manifest_path = GetManifestPath();
428 if (!manifest_path.empty()) {
429 cmd_line.AppendArg("--eval-command");
430 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
431 manifest_path.value());
432 }
433 cmd_line.AppendArg("--eval-command");
434 cmd_line.AppendArg("attach " + base::IntToString(pid));
435 int fds[2];
436 if (pipe(fds) != 0)
437 return false;
438 // Tell the debugger to send a byte to the writable end of the pipe.
439 // We use a file descriptor in our process because the debugger will be
440 // typically launched in a separate terminal, and a lot of terminals close all
441 // file descriptors before launching external programs.
442 cmd_line.AppendArg("--eval-command");
443 cmd_line.AppendArg("dump binary value /proc/" +
444 base::IntToString(base::GetCurrentProcId()) +
445 "/fd/" + base::IntToString(fds[1]) + " (char)0");
[email protected]401b90792012-05-30 11:41:13446 FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
447 switches::kNaClGdbScript);
448 if (!script.empty()) {
449 cmd_line.AppendArg("--command");
450 cmd_line.AppendArgNative(script.value());
451 }
[email protected]5b974952012-04-05 18:18:23452 // wait on fds[0]
453 // If the debugger crashes before attaching to the NaCl process, the user can
454 // release resources by terminating the NaCl loader in Chrome Task Manager.
455 nacl_gdb_watcher_delegate_.reset(
456 new NaClGdbWatchDelegate(
457 fds[0], fds[1],
458 base::Bind(&NaClProcessHost::OnNaClGdbAttached,
459 weak_factory_.GetWeakPtr())));
460 MessageLoopForIO::current()->WatchFileDescriptor(
461 fds[0],
462 true,
463 MessageLoopForIO::WATCH_READ,
464 &nacl_gdb_watcher_,
465 nacl_gdb_watcher_delegate_.get());
466 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
467}
468
469void NaClProcessHost::OnNaClGdbAttached() {
470 wait_for_nacl_gdb_ = false;
471 nacl_gdb_watcher_.StopWatchingFileDescriptor();
472 nacl_gdb_watcher_delegate_.reset();
473 OnProcessLaunched();
474}
475#endif
476
477FilePath NaClProcessHost::GetManifestPath() {
[email protected]1c321ee2012-05-21 03:02:34478 const extensions::Extension* extension = extension_info_map_->extensions()
[email protected]87f35592012-04-08 00:49:16479 .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url_));
[email protected]885c0e92012-11-13 20:27:42480 if (extension != NULL &&
481 manifest_url_.SchemeIs(extensions::kExtensionScheme)) {
[email protected]87f35592012-04-08 00:49:16482 std::string path = manifest_url_.path();
[email protected]5b974952012-04-05 18:18:23483 TrimString(path, "/", &path); // Remove first slash
484 return extension->path().AppendASCII(path);
485 }
486 return FilePath();
487}
[email protected]31a665e72012-03-11 12:37:46488
[email protected]fb1277e82009-11-21 20:32:30489bool NaClProcessHost::LaunchSelLdr() {
[email protected]4967f792012-01-20 22:14:40490 std::string channel_id = process_->GetHost()->CreateChannel();
[email protected]4734d0b2011-12-03 07:10:44491 if (channel_id.empty())
[email protected]d032f492009-09-29 00:33:46492 return false;
493
[email protected]e3fc75a2011-05-05 08:20:42494 CommandLine::StringType nacl_loader_prefix;
495#if defined(OS_POSIX)
496 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
497 switches::kNaClLoaderCmdPrefix);
498#endif // defined(OS_POSIX)
499
[email protected]d032f492009-09-29 00:33:46500 // Build command line for nacl.
[email protected]8c40f322011-08-24 03:33:36501
502#if defined(OS_MACOSX)
503 // The Native Client process needs to be able to allocate a 1GB contiguous
504 // region to use as the client environment's virtual address space. ASLR
505 // (PIE) interferes with this by making it possible that no gap large enough
506 // to accomodate this request will exist in the child process' address
507 // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
508 // http://code.google.com/p/nativeclient/issues/detail?id=2043.
[email protected]4cb43102011-12-02 20:24:49509 int flags = ChildProcessHost::CHILD_NO_PIE;
[email protected]8c40f322011-08-24 03:33:36510#elif defined(OS_LINUX)
[email protected]4cb43102011-12-02 20:24:49511 int flags = nacl_loader_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
512 ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36513#else
[email protected]4cb43102011-12-02 20:24:49514 int flags = ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36515#endif
516
[email protected]4cb43102011-12-02 20:24:49517 FilePath exe_path = ChildProcessHost::GetChildPath(flags);
[email protected]fb1277e82009-11-21 20:32:30518 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46519 return false;
520
[email protected]31a665e72012-03-11 12:37:46521#if defined(OS_WIN)
522 // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
523 if (RunningOnWOW64()) {
524 FilePath module_path;
525 if (!PathService::Get(base::FILE_MODULE, &module_path))
526 return false;
527 exe_path = module_path.DirName().Append(chrome::kNaClAppName);
528 }
529#endif
530
[email protected]33a05af2012-03-02 18:15:51531 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
532 nacl::CopyNaClCommandLineArguments(cmd_line.get());
[email protected]599e6642010-01-27 18:52:13533
[email protected]05076ba22010-07-30 05:59:57534 cmd_line->AppendSwitchASCII(switches::kProcessType,
535 switches::kNaClLoaderProcess);
[email protected]4734d0b2011-12-03 07:10:44536 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
[email protected]93156cec2011-09-12 21:14:44537 if (logging::DialogsAreSuppressed())
538 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
[email protected]d032f492009-09-29 00:33:46539
[email protected]e3fc75a2011-05-05 08:20:42540 if (!nacl_loader_prefix.empty())
541 cmd_line->PrependWrapper(nacl_loader_prefix);
542
[email protected]31a665e72012-03-11 12:37:46543 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
544 switches::kNaClGdb);
545 if (!nacl_gdb.empty()) {
[email protected]5b974952012-04-05 18:18:23546#if defined(OS_WIN)
[email protected]31a665e72012-03-11 12:37:46547 cmd_line->AppendSwitch(switches::kNoSandbox);
548 scoped_ptr<CommandLine> gdb_cmd_line(
[email protected]646e15552012-04-06 22:01:04549 GetCommandForLaunchWithGdb(nacl_gdb, cmd_line.get()));
[email protected]31a665e72012-03-11 12:37:46550 // We can't use process_->Launch() because OnProcessLaunched will be called
551 // with process_->GetData().handle filled by handle of gdb process. This
552 // handle will be used to duplicate handles for NaCl process and as
553 // a result NaCl process will not be able to use them.
554 //
555 // So we don't fill process_->GetData().handle and wait for
556 // OnChannelConnected to get handle of NaCl process from its pid. Then we
557 // call OnProcessLaunched.
558 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL);
[email protected]5b974952012-04-05 18:18:23559#elif defined(OS_LINUX)
560 wait_for_nacl_gdb_ = true;
561#endif
[email protected]31a665e72012-03-11 12:37:46562 }
563
[email protected]103607e2010-02-01 18:57:09564 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46565#if defined(OS_WIN)
[email protected]773ebb92011-11-15 19:06:52566 if (RunningOnWOW64()) {
[email protected]26b3c002012-04-26 19:38:34567 return NaClBrokerService::GetInstance()->LaunchLoader(
568 weak_factory_.GetWeakPtr(), channel_id);
[email protected]4bdde602010-06-16 03:17:35569 } else {
[email protected]33a05af2012-03-02 18:15:51570 process_->Launch(FilePath(), cmd_line.release());
[email protected]4bdde602010-06-16 03:17:35571 }
[email protected]103607e2010-02-01 18:57:09572#elif defined(OS_POSIX)
[email protected]4967f792012-01-20 22:14:40573 process_->Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]a82af392012-02-24 04:40:20574 base::EnvironmentVector(),
[email protected]33a05af2012-03-02 18:15:51575 cmd_line.release());
[email protected]103607e2010-02-01 18:57:09576#endif
[email protected]d032f492009-09-29 00:33:46577
[email protected]fb1277e82009-11-21 20:32:30578 return true;
[email protected]d032f492009-09-29 00:33:46579}
580
[email protected]646e15552012-04-06 22:01:04581bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
582 bool handled = true;
583 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
584 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
585 OnQueryKnownToValidate)
586 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
587 OnSetKnownToValidate)
[email protected]ea6588842012-05-03 05:39:38588#if defined(OS_WIN)
589 IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_AttachDebugExceptionHandler,
590 OnAttachDebugExceptionHandler)
591#endif
[email protected]17b5a8172012-06-22 21:09:09592 IPC_MESSAGE_HANDLER(NaClProcessHostMsg_PpapiChannelCreated,
593 OnPpapiChannelCreated)
[email protected]646e15552012-04-06 22:01:04594 IPC_MESSAGE_UNHANDLED(handled = false)
595 IPC_END_MESSAGE_MAP()
596 return handled;
[email protected]103607e2010-02-01 18:57:09597}
598
[email protected]773ebb92011-11-15 19:06:52599void NaClProcessHost::OnProcessLaunched() {
[email protected]09afc2e2012-04-10 17:29:03600 if (!StartWithLaunchedProcess())
601 delete this;
[email protected]773ebb92011-11-15 19:06:52602}
603
[email protected]e97990f2012-05-15 22:06:06604// Called when the NaClBrowser singleton has been fully initialized.
605void NaClProcessHost::OnResourcesReady() {
[email protected]773ebb92011-11-15 19:06:52606 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]e97990f2012-05-15 22:06:06607 if (!nacl_browser->IsReady() || !SendStart()) {
[email protected]09afc2e2012-04-10 17:29:03608 DLOG(ERROR) << "Cannot launch NaCl process";
[email protected]338466a82011-05-03 04:27:43609 delete this;
610 }
611}
612
[email protected]17b5a8172012-06-22 21:09:09613bool NaClProcessHost::ReplyToRenderer(
614 const IPC::ChannelHandle& channel_handle) {
[email protected]6294dd02013-01-09 17:27:23615 nacl::FileDescriptor handle_for_renderer;
[email protected]c47ec402010-07-29 10:20:49616#if defined(OS_WIN)
[email protected]6294dd02013-01-09 17:27:23617 // Copy the handle into the renderer process.
618 HANDLE handle_in_renderer;
619 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
620 reinterpret_cast<HANDLE>(
621 internal_->socket_for_renderer),
622 chrome_render_message_filter_->peer_handle(),
623 &handle_in_renderer,
624 0, // Unused given DUPLICATE_SAME_ACCESS.
625 FALSE,
626 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
627 DLOG(ERROR) << "DuplicateHandle() failed";
628 return false;
[email protected]c47ec402010-07-29 10:20:49629 }
[email protected]6294dd02013-01-09 17:27:23630 handle_for_renderer = reinterpret_cast<nacl::FileDescriptor>(
631 handle_in_renderer);
632#else
633 // No need to dup the imc_handle - we don't pass it anywhere else so
634 // it cannot be closed.
635 nacl::FileDescriptor imc_handle;
636 imc_handle.fd = internal_->socket_for_renderer;
637 imc_handle.auto_close = true;
638 handle_for_renderer = imc_handle;
639#endif
[email protected]c47ec402010-07-29 10:20:49640
641#if defined(OS_WIN)
[email protected]e4f6eb0232012-04-17 00:47:50642 // If we are on 64-bit Windows, the NaCl process's sandbox is
643 // managed by a different process from the renderer's sandbox. We
644 // need to inform the renderer's sandbox about the NaCl process so
645 // that the renderer can send handles to the NaCl process using
646 // BrokerDuplicateHandle().
647 if (RunningOnWOW64()) {
[email protected]171fa98d2012-04-23 21:34:01648 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
[email protected]e4f6eb0232012-04-17 00:47:50649 DLOG(ERROR) << "Failed to add NaCl process PID";
650 return false;
651 }
652 }
[email protected]fb1277e82009-11-21 20:32:30653#endif
654
[email protected]108fd342013-01-04 20:46:54655 const ChildProcessData& data = process_->GetData();
[email protected]2ccf45c2011-08-19 23:35:50656 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]6294dd02013-01-09 17:27:23657 reply_msg_, handle_for_renderer,
[email protected]108fd342013-01-04 20:46:54658 channel_handle, base::GetProcId(data.handle), data.id);
[email protected]92d56412011-03-24 20:53:52659 chrome_render_message_filter_->Send(reply_msg_);
660 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30661 reply_msg_ = NULL;
[email protected]6294dd02013-01-09 17:27:23662 internal_->socket_for_renderer = nacl::kInvalidHandle;
[email protected]00d99542012-04-17 22:48:02663 return true;
664}
[email protected]fb1277e82009-11-21 20:32:30665
[email protected]d571c032012-09-14 12:39:18666// TCP port we chose for NaCl debug stub. It can be any other number.
667static const int kDebugStubPort = 4014;
668
669#if defined(OS_POSIX)
670SocketDescriptor NaClProcessHost::GetDebugStubSocketHandle() {
[email protected]13cad0b2012-12-07 17:57:34671 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
672 SocketDescriptor s;
673 // We allocate currently unused TCP port for debug stub tests. The port
674 // number is passed to the test via debug stub port listener.
675 if (nacl_browser->HasGdbDebugStubPortListener()) {
676 int port;
677 s = net::TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port);
678 if (s != net::TCPListenSocket::kInvalidSocket) {
679 nacl_browser->FireGdbDebugStubPortOpened(port);
680 }
681 } else {
682 s = net::TCPListenSocket::CreateAndBind("127.0.0.1", kDebugStubPort);
683 }
684 if (s == net::TCPListenSocket::kInvalidSocket) {
685 LOG(ERROR) << "failed to open socket for debug stub";
686 return net::TCPListenSocket::kInvalidSocket;
687 }
[email protected]d571c032012-09-14 12:39:18688 if (listen(s, 1)) {
689 LOG(ERROR) << "listen() failed on debug stub socket";
[email protected]13cad0b2012-12-07 17:57:34690 if (HANDLE_EINTR(close(s)) < 0)
691 PLOG(ERROR) << "failed to close debug stub socket";
[email protected]d571c032012-09-14 12:39:18692 return net::TCPListenSocket::kInvalidSocket;
693 }
694 return s;
695}
696#endif
697
[email protected]00d99542012-04-17 22:48:02698bool NaClProcessHost::StartNaClExecution() {
699 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
700
701 nacl::NaClStartParams params;
[email protected]8c670832012-05-26 04:30:12702 params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
703 params.validation_cache_key = nacl_browser->GetValidationCacheKey();
[email protected]00d99542012-04-17 22:48:02704 params.version = chrome::VersionInfo().CreateVersionString();
705 params.enable_exception_handling = enable_exception_handling_;
[email protected]66f409c2012-10-04 20:59:04706 params.enable_debug_stub = enable_debug_stub_ &&
707 NaClBrowser::GetInstance()->URLMatchesDebugPatterns(manifest_url_);
[email protected]17b5a8172012-06-22 21:09:09708 params.enable_ipc_proxy = enable_ipc_proxy_;
[email protected]00d99542012-04-17 22:48:02709
710 base::PlatformFile irt_file = nacl_browser->IrtFile();
711 CHECK_NE(irt_file, base::kInvalidPlatformFileValue);
712
713 const ChildProcessData& data = process_->GetData();
[email protected]6294dd02013-01-09 17:27:23714 if (!ShareHandleToSelLdr(data.handle,
715 internal_->socket_for_sel_ldr, true,
716 &params.handles)) {
717 return false;
[email protected]773ebb92011-11-15 19:06:52718 }
719
720 // Send over the IRT file handle. We don't close our own copy!
[email protected]00d99542012-04-17 22:48:02721 if (!ShareHandleToSelLdr(data.handle, irt_file, false, &params.handles))
[email protected]09afc2e2012-04-10 17:29:03722 return false;
[email protected]c47ec402010-07-29 10:20:49723
[email protected]ab88d1542011-11-18 22:52:00724#if defined(OS_MACOSX)
725 // For dynamic loading support, NaCl requires a file descriptor that
726 // was created in /tmp, since those created with shm_open() are not
727 // mappable with PROT_EXEC. Rather than requiring an extra IPC
728 // round trip out of the sandbox, we create an FD here.
[email protected]cbbe7842011-11-17 22:01:25729 base::SharedMemory memory_buffer;
[email protected]b05df6b2011-12-01 23:19:31730 base::SharedMemoryCreateOptions options;
731 options.size = 1;
732 options.executable = true;
733 if (!memory_buffer.Create(options)) {
[email protected]09afc2e2012-04-10 17:29:03734 DLOG(ERROR) << "Failed to allocate memory buffer";
735 return false;
[email protected]2c68bf032010-11-11 23:16:30736 }
[email protected]cbbe7842011-11-17 22:01:25737 nacl::FileDescriptor memory_fd;
738 memory_fd.fd = dup(memory_buffer.handle().fd);
739 if (memory_fd.fd < 0) {
[email protected]09afc2e2012-04-10 17:29:03740 DLOG(ERROR) << "Failed to dup() a file descriptor";
741 return false;
[email protected]cbbe7842011-11-17 22:01:25742 }
743 memory_fd.auto_close = true;
[email protected]00d99542012-04-17 22:48:02744 params.handles.push_back(memory_fd);
[email protected]2c68bf032010-11-11 23:16:30745#endif
746
[email protected]d571c032012-09-14 12:39:18747#if defined(OS_POSIX)
[email protected]ed637bb2012-10-15 17:36:05748 if (params.enable_debug_stub) {
[email protected]d571c032012-09-14 12:39:18749 SocketDescriptor server_bound_socket = GetDebugStubSocketHandle();
750 if (server_bound_socket != net::TCPListenSocket::kInvalidSocket) {
751 params.debug_stub_server_bound_socket =
752 nacl::FileDescriptor(server_bound_socket, true);
753 }
754 }
755#endif
756
[email protected]ea6588842012-05-03 05:39:38757 process_->Send(new NaClProcessMsg_Start(params));
[email protected]b39c6d92012-01-31 16:38:41758
[email protected]6294dd02013-01-09 17:27:23759 internal_->socket_for_sel_ldr = nacl::kInvalidHandle;
[email protected]09afc2e2012-04-10 17:29:03760 return true;
761}
762
[email protected]00d99542012-04-17 22:48:02763bool NaClProcessHost::SendStart() {
[email protected]17b5a8172012-06-22 21:09:09764 if (!enable_ipc_proxy_) {
765 if (!ReplyToRenderer(IPC::ChannelHandle()))
766 return false;
767 }
768 return StartNaClExecution();
769}
770
[email protected]8510d282012-08-30 19:47:38771// This method is called when NaClProcessHostMsg_PpapiChannelCreated is
772// received or PpapiHostMsg_ChannelCreated is forwarded by our plugin
773// listener.
[email protected]17b5a8172012-06-22 21:09:09774void NaClProcessHost::OnPpapiChannelCreated(
775 const IPC::ChannelHandle& channel_handle) {
776 DCHECK(enable_ipc_proxy_);
[email protected]8510d282012-08-30 19:47:38777 // If the proxy channel is null, this must be the initial NaCl-Browser IPC
778 // channel.
779 if (!ipc_proxy_channel_.get()) {
780 ipc_proxy_channel_.reset(
781 new IPC::ChannelProxy(channel_handle,
782 IPC::Channel::MODE_CLIENT,
783 &ipc_plugin_listener_,
784 base::MessageLoopProxy::current()));
[email protected]0c7193742012-11-07 19:05:03785 // Create the browser ppapi host and enable PPAPI message dispatching to the
786 // browser process.
[email protected]adf7cd52012-12-04 19:37:46787 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
788 ipc_proxy_channel_.get(), //process_.get(), // sender
[email protected]0c7193742012-11-07 19:05:03789 permissions_,
790 process_->GetData().handle,
[email protected]b4b53d182012-09-12 02:56:55791 ipc_proxy_channel_.get(),
[email protected]e02ff722012-11-06 03:53:06792 chrome_render_message_filter_->GetHostResolver(),
793 chrome_render_message_filter_->render_process_id(),
[email protected]adf7cd52012-12-04 19:37:46794 render_view_id_));
795
[email protected]8510d282012-08-30 19:47:38796 // Send a message to create the NaCl-Renderer channel. The handle is just
797 // a place holder.
798 ipc_proxy_channel_->Send(
799 new PpapiMsg_CreateNaClChannel(
800 chrome_render_message_filter_->render_process_id(),
[email protected]195d4cde2012-10-02 18:12:41801 permissions_,
[email protected]8510d282012-08-30 19:47:38802 chrome_render_message_filter_->off_the_record(),
803 SerializedHandle(SerializedHandle::CHANNEL_HANDLE,
804 IPC::InvalidPlatformFileForTransit())));
805 } else if (reply_msg_) {
806 // Otherwise, this must be a renderer channel.
807 ReplyToRenderer(channel_handle);
808 } else {
809 // Attempt to open more than 1 renderer channel is not supported.
810 // Shut down the NaCl process.
811 process_->GetHost()->ForceShutdown();
812 }
813}
814
815bool NaClProcessHost::OnUntrustedMessageForwarded(const IPC::Message& msg) {
816 // Handle messages that have been forwarded from our PluginListener.
817 // These messages come from untrusted code so should be handled with care.
818 bool handled = true;
819 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
820 IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated,
821 OnPpapiChannelCreated)
822 IPC_MESSAGE_UNHANDLED(handled = false)
823 IPC_END_MESSAGE_MAP()
824 return handled;
[email protected]00d99542012-04-17 22:48:02825}
826
[email protected]09afc2e2012-04-10 17:29:03827bool NaClProcessHost::StartWithLaunchedProcess() {
828#if defined(OS_LINUX)
829 if (wait_for_nacl_gdb_) {
830 if (LaunchNaClGdb(base::GetProcId(process_->GetData().handle))) {
831 // We will be called with wait_for_nacl_gdb_ = false once debugger is
832 // attached to the program.
833 return true;
834 }
835 DLOG(ERROR) << "Failed to launch debugger";
836 // Continue execution without debugger.
837 }
838#endif
839
840 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]09afc2e2012-04-10 17:29:03841
[email protected]e97990f2012-05-15 22:06:06842 if (nacl_browser->IsReady()) {
843 return SendStart();
844 } else if (nacl_browser->IsOk()) {
845 nacl_browser->WaitForResources(
846 base::Bind(&NaClProcessHost::OnResourcesReady,
847 weak_factory_.GetWeakPtr()));
848 return true;
849 } else {
850 return false;
851 }
[email protected]d032f492009-09-29 00:33:46852}
853
[email protected]4a0141b2012-03-27 01:15:30854void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
855 bool* result) {
[email protected]7cfaf982012-05-09 18:37:47856 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]57473ebc2012-05-30 07:44:52857 *result = nacl_browser->QueryKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30858}
859
860void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
[email protected]57473ebc2012-05-30 07:44:52861 NaClBrowser::GetInstance()->SetKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30862}
[email protected]ea6588842012-05-03 05:39:38863
864#if defined(OS_WIN)
865void NaClProcessHost::OnAttachDebugExceptionHandler(const std::string& info,
866 IPC::Message* reply_msg) {
867 if (!AttachDebugExceptionHandler(info, reply_msg)) {
868 // Send failure message.
869 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply_msg,
870 false);
871 Send(reply_msg);
872 }
873}
874
875bool NaClProcessHost::AttachDebugExceptionHandler(const std::string& info,
876 IPC::Message* reply_msg) {
[email protected]2c227ff2012-08-11 00:51:32877 if (!enable_exception_handling_ && !enable_debug_stub_) {
[email protected]ea6588842012-05-03 05:39:38878 DLOG(ERROR) <<
[email protected]2c227ff2012-08-11 00:51:32879 "Debug exception handler requested by NaCl process when not enabled";
[email protected]ea6588842012-05-03 05:39:38880 return false;
881 }
882 if (debug_exception_handler_requested_) {
883 // The NaCl process should not request this multiple times.
884 DLOG(ERROR) << "Multiple AttachDebugExceptionHandler requests received";
885 return false;
886 }
887 debug_exception_handler_requested_ = true;
888
889 base::ProcessId nacl_pid = base::GetProcId(process_->GetData().handle);
890 base::win::ScopedHandle process_handle;
891 // We cannot use process_->GetData().handle because it does not have
892 // the necessary access rights. We open the new handle here rather
893 // than in the NaCl broker process in case the NaCl loader process
894 // dies before the NaCl broker process receives the message we send.
895 // The debug exception handler uses DebugActiveProcess() to attach,
896 // but this takes a PID. We need to prevent the NaCl loader's PID
897 // from being reused before DebugActiveProcess() is called, and
898 // holding a process handle open achieves this.
899 if (!base::OpenProcessHandleWithAccess(
900 nacl_pid,
901 base::kProcessAccessQueryInformation |
902 base::kProcessAccessSuspendResume |
903 base::kProcessAccessTerminate |
904 base::kProcessAccessVMOperation |
905 base::kProcessAccessVMRead |
906 base::kProcessAccessVMWrite |
[email protected]29172322013-01-10 17:35:16907 base::kProcessAccessDuplicateHandle |
[email protected]ea6588842012-05-03 05:39:38908 base::kProcessAccessWaitForTermination,
909 process_handle.Receive())) {
910 LOG(ERROR) << "Failed to get process handle";
911 return false;
912 }
913
914 attach_debug_exception_handler_reply_msg_.reset(reply_msg);
915 // If the NaCl loader is 64-bit, the process running its debug
916 // exception handler must be 64-bit too, so we use the 64-bit NaCl
917 // broker process for this. Otherwise, on a 32-bit system, we use
918 // the 32-bit browser process to run the debug exception handler.
919 if (RunningOnWOW64()) {
920 return NaClBrokerService::GetInstance()->LaunchDebugExceptionHandler(
[email protected]fd37bf62012-05-04 16:46:48921 weak_factory_.GetWeakPtr(), nacl_pid, process_handle, info);
[email protected]ea6588842012-05-03 05:39:38922 } else {
923 NaClStartDebugExceptionHandlerThread(
[email protected]fd37bf62012-05-04 16:46:48924 process_handle.Take(), info,
[email protected]ea6588842012-05-03 05:39:38925 base::MessageLoopProxy::current(),
926 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
927 weak_factory_.GetWeakPtr()));
928 return true;
929 }
930}
931#endif