blob: f7134485ff4c3f2d6fde1168ccee0613b431efae [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]04284252013-06-11 22:30:147#include <algorithm>
[email protected]a82af392012-02-24 04:40:208#include <string>
9#include <vector>
[email protected]d032f492009-09-29 00:33:4610
[email protected]ac07ec52013-04-22 17:32:4511#include "base/base_switches.h"
[email protected]30c1eea2011-10-17 18:40:3012#include "base/bind.h"
[email protected]103607e2010-02-01 18:57:0913#include "base/command_line.h"
[email protected]6d7f55f2013-05-14 10:12:5614#include "base/file_util.h"
[email protected]5b974952012-04-05 18:18:2315#include "base/message_loop.h"
[email protected]9addd1c2012-09-15 14:28:2416#include "base/metrics/histogram.h"
[email protected]338466a82011-05-03 04:27:4317#include "base/path_service.h"
[email protected]108fd342013-01-04 20:46:5418#include "base/process_util.h"
[email protected]3ea1b182013-02-08 22:38:4119#include "base/strings/string_number_conversions.h"
[email protected]1988e1c2013-02-28 20:27:4220#include "base/strings/string_split.h"
[email protected]f9b294362013-06-10 20:22:3121#include "base/strings/string_util.h"
22#include "base/strings/stringprintf.h"
[email protected]112158af2013-06-07 23:46:1823#include "base/strings/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3724#include "base/win/windows_version.h"
[email protected]a82af392012-02-24 04:40:2025#include "build/build_config.h"
[email protected]2e5f2ea42012-05-09 21:39:2126#include "chrome/browser/nacl_host/nacl_browser.h"
[email protected]01e59752013-06-18 00:17:3527#include "chrome/browser/nacl_host/nacl_host_message_filter.h"
[email protected]4b30e7d2013-04-24 23:52:1428#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
[email protected]338466a82011-05-03 04:27:4329#include "chrome/common/chrome_paths.h"
[email protected]f3b357692013-03-22 05:16:1330#include "chrome/common/chrome_process_type.h"
[email protected]d032f492009-09-29 00:33:4631#include "chrome/common/chrome_switches.h"
[email protected]1657e6d2012-03-30 20:28:0032#include "chrome/common/chrome_version_info.h"
[email protected]d032f492009-09-29 00:33:4633#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0934#include "chrome/common/nacl_cmd_line.h"
[email protected]01e59752013-06-18 00:17:3535#include "chrome/common/nacl_host_messages.h"
[email protected]d032f492009-09-29 00:33:4636#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3037#include "chrome/common/render_messages.h"
[email protected]cbb22eb2013-06-24 23:53:1038#include "components/nacl/common/nacl_switches.h"
[email protected]4967f792012-01-20 22:14:4039#include "content/public/browser/browser_child_process_host.h"
[email protected]0c7193742012-11-07 19:05:0340#include "content/public/browser/browser_ppapi_host.h"
[email protected]4967f792012-01-20 22:14:4041#include "content/public/browser/child_process_data.h"
[email protected]4734d0b2011-12-03 07:10:4442#include "content/public/common/child_process_host.h"
[email protected]9e141212013-01-21 15:21:5643#include "content/public/common/process_type.h"
[email protected]8510d282012-08-30 19:47:3844#include "ipc/ipc_channel.h"
[email protected]d032f492009-09-29 00:33:4645#include "ipc/ipc_switches.h"
[email protected]c8e1ea32013-02-13 02:19:0146#include "native_client/src/shared/imc/nacl_imc_c.h"
[email protected]87f35592012-04-08 00:49:1647#include "net/base/net_util.h"
[email protected]1946d9e2013-04-09 01:43:3748#include "net/socket/tcp_listen_socket.h"
[email protected]4b30e7d2013-04-24 23:52:1449#include "ppapi/host/ppapi_host.h"
[email protected]8510d282012-08-30 19:47:3850#include "ppapi/proxy/ppapi_messages.h"
[email protected]ac07ec52013-04-22 17:32:4551#include "ppapi/shared_impl/ppapi_nacl_channel_args.h"
[email protected]d032f492009-09-29 00:33:4652
[email protected]d032f492009-09-29 00:33:4653#if defined(OS_POSIX)
[email protected]a82af392012-02-24 04:40:2054#include <fcntl.h>
55
[email protected]d032f492009-09-29 00:33:4656#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3557#elif defined(OS_WIN)
[email protected]a82af392012-02-24 04:40:2058#include <windows.h>
59
[email protected]885c0e92012-11-13 20:27:4260#include "base/threading/thread.h"
[email protected]4c65fb632012-04-27 00:42:2561#include "base/win/scoped_handle.h"
[email protected]4bdde602010-06-16 03:17:3562#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]ea6588842012-05-03 05:39:3863#include "chrome/common/nacl_debug_exception_handler_win.h"
[email protected]e4f6eb0232012-04-17 00:47:5064#include "content/public/common/sandbox_init.h"
[email protected]34f48682013-03-20 00:30:1865#include "content/public/common/sandboxed_process_launcher_delegate.h"
[email protected]d032f492009-09-29 00:33:4666#endif
67
[email protected]631bb742011-11-02 11:29:3968using content::BrowserThread;
[email protected]4967f792012-01-20 22:14:4069using content::ChildProcessData;
[email protected]4734d0b2011-12-03 07:10:4470using content::ChildProcessHost;
[email protected]8510d282012-08-30 19:47:3871using ppapi::proxy::SerializedHandle;
[email protected]631bb742011-11-02 11:29:3972
[email protected]646e15552012-04-06 22:01:0473namespace {
74
75#if defined(OS_WIN)
76bool RunningOnWOW64() {
77 return (base::win::OSInfo::GetInstance()->wow64_status() ==
78 base::win::OSInfo::WOW64_ENABLED);
79}
[email protected]34f48682013-03-20 00:30:1880
81// NOTE: changes to this class need to be reviewed by the security team.
82class NaClSandboxedProcessLauncherDelegate
83 : public content::SandboxedProcessLauncherDelegate {
84 public:
85 NaClSandboxedProcessLauncherDelegate() {}
86 virtual ~NaClSandboxedProcessLauncherDelegate() {}
87
88 virtual void PostSpawnTarget(base::ProcessHandle process) {
89#if !defined(NACL_WIN64)
90 // For Native Client sel_ldr processes on 32-bit Windows, reserve 1 GB of
91 // address space to prevent later failure due to address space fragmentation
92 // from .dll loading. The NaCl process will attempt to locate this space by
93 // scanning the address space using VirtualQuery.
94 // TODO(bbudge) Handle the --no-sandbox case.
95 // http://code.google.com/p/nativeclient/issues/detail?id=2131
96 const SIZE_T kOneGigabyte = 1 << 30;
97 void* nacl_mem = VirtualAllocEx(process,
98 NULL,
99 kOneGigabyte,
100 MEM_RESERVE,
101 PAGE_NOACCESS);
102 if (!nacl_mem) {
103 DLOG(WARNING) << "Failed to reserve address space for Native Client";
104 }
105#endif // !defined(NACL_WIN64)
106 }
107};
108
109#endif // OS_WIN
[email protected]646e15552012-04-06 22:01:04110
[email protected]c8e1ea32013-02-13 02:19:01111void SetCloseOnExec(NaClHandle fd) {
[email protected]646e15552012-04-06 22:01:04112#if defined(OS_POSIX)
113 int flags = fcntl(fd, F_GETFD);
114 CHECK_NE(flags, -1);
115 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
116 CHECK_EQ(rc, 0);
117#endif
118}
119
[email protected]00d99542012-04-17 22:48:02120bool ShareHandleToSelLdr(
[email protected]646e15552012-04-06 22:01:04121 base::ProcessHandle processh,
[email protected]c8e1ea32013-02-13 02:19:01122 NaClHandle sourceh,
[email protected]646e15552012-04-06 22:01:04123 bool close_source,
124 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
125#if defined(OS_WIN)
126 HANDLE channel;
127 int flags = DUPLICATE_SAME_ACCESS;
128 if (close_source)
129 flags |= DUPLICATE_CLOSE_SOURCE;
130 if (!DuplicateHandle(GetCurrentProcess(),
131 reinterpret_cast<HANDLE>(sourceh),
132 processh,
133 &channel,
134 0, // Unused given DUPLICATE_SAME_ACCESS.
135 FALSE,
136 flags)) {
[email protected]ec7540f2013-01-17 00:00:35137 LOG(ERROR) << "DuplicateHandle() failed";
[email protected]646e15552012-04-06 22:01:04138 return false;
139 }
140 handles_for_sel_ldr->push_back(
141 reinterpret_cast<nacl::FileDescriptor>(channel));
142#else
143 nacl::FileDescriptor channel;
144 channel.fd = sourceh;
145 channel.auto_close = close_source;
146 handles_for_sel_ldr->push_back(channel);
147#endif
148 return true;
149}
150
[email protected]27b04df2012-12-10 23:43:10151ppapi::PpapiPermissions GetNaClPermissions(uint32 permission_bits) {
152 // Only allow NaCl plugins to request certain permissions. We don't want
153 // a compromised renderer to be able to start a nacl plugin with e.g. Flash
154 // permissions which may expand the surface area of the sandbox.
155 uint32 masked_bits = permission_bits & ppapi::PERMISSION_DEV;
156 return ppapi::PpapiPermissions::GetForCommandLine(masked_bits);
157}
158
[email protected]646e15552012-04-06 22:01:04159} // namespace
160
[email protected]1d8a3d1f2011-02-19 07:11:52161struct NaClProcessHost::NaClInternal {
[email protected]c8e1ea32013-02-13 02:19:01162 NaClHandle socket_for_renderer;
163 NaClHandle socket_for_sel_ldr;
[email protected]6294dd02013-01-09 17:27:23164
165 NaClInternal()
[email protected]c8e1ea32013-02-13 02:19:01166 : socket_for_renderer(NACL_INVALID_HANDLE),
167 socket_for_sel_ldr(NACL_INVALID_HANDLE) { }
[email protected]1d8a3d1f2011-02-19 07:11:52168};
169
[email protected]646e15552012-04-06 22:01:04170// -----------------------------------------------------------------------------
[email protected]773ebb92011-11-15 19:06:52171
[email protected]8510d282012-08-30 19:47:38172NaClProcessHost::PluginListener::PluginListener(NaClProcessHost* host)
173 : host_(host) {
174}
175
176bool NaClProcessHost::PluginListener::OnMessageReceived(
177 const IPC::Message& msg) {
178 return host_->OnUntrustedMessageForwarded(msg);
179}
180
[email protected]9da4fed2012-11-01 17:07:55181NaClProcessHost::NaClProcessHost(const GURL& manifest_url,
[email protected]e02ff722012-11-06 03:53:06182 int render_view_id,
[email protected]9da4fed2012-11-01 17:07:55183 uint32 permission_bits,
[email protected]2e1e6f02013-01-11 18:22:56184 bool uses_irt,
[email protected]be524622013-04-23 00:12:19185 bool enable_dyncode_syscalls,
[email protected]286c0952013-06-13 20:29:26186 bool enable_exception_handling,
[email protected]7bb5d2c2013-04-29 22:33:49187 bool off_the_record,
188 const base::FilePath& profile_directory)
[email protected]87f35592012-04-08 00:49:16189 : manifest_url_(manifest_url),
[email protected]27b04df2012-12-10 23:43:10190 permissions_(GetNaClPermissions(permission_bits)),
[email protected]a575da52012-03-22 13:08:36191#if defined(OS_WIN)
192 process_launched_by_broker_(false),
193#endif
194 reply_msg_(NULL),
[email protected]ea6588842012-05-03 05:39:38195#if defined(OS_WIN)
196 debug_exception_handler_requested_(false),
197#endif
[email protected]1d8a3d1f2011-02-19 07:11:52198 internal_(new NaClInternal()),
[email protected]9c009092013-05-01 03:14:09199 weak_factory_(this),
[email protected]84b8e8962013-06-12 22:24:06200 uses_irt_(uses_irt),
[email protected]286c0952013-06-13 20:29:26201 enable_debug_stub_(false),
[email protected]be524622013-04-23 00:12:19202 enable_dyncode_syscalls_(enable_dyncode_syscalls),
[email protected]286c0952013-06-13 20:29:26203 enable_exception_handling_(enable_exception_handling),
[email protected]8510d282012-08-30 19:47:38204 off_the_record_(off_the_record),
[email protected]7bb5d2c2013-04-29 22:33:49205 profile_directory_(profile_directory),
[email protected]9c009092013-05-01 03:14:09206 ipc_plugin_listener_(this),
[email protected]e02ff722012-11-06 03:53:06207 render_view_id_(render_view_id) {
[email protected]4967f792012-01-20 22:14:40208 process_.reset(content::BrowserChildProcessHost::Create(
[email protected]f3b357692013-03-22 05:16:13209 PROCESS_TYPE_NACL_LOADER, this));
[email protected]87f35592012-04-08 00:49:16210
211 // Set the display name so the user knows what plugin the process is running.
212 // We aren't on the UI thread so getting the pref locale for language
213 // formatting isn't possible, so IDN will be lost, but this is probably OK
214 // for this use case.
215 process_->SetName(net::FormatUrl(manifest_url_, std::string()));
[email protected]5ca93be2012-03-21 20:04:06216
[email protected]2c227ff2012-08-11 00:51:32217 enable_debug_stub_ = CommandLine::ForCurrentProcess()->HasSwitch(
218 switches::kEnableNaClDebug);
[email protected]d032f492009-09-29 00:33:46219}
220
[email protected]fb1277e82009-11-21 20:32:30221NaClProcessHost::~NaClProcessHost() {
[email protected]4cb43102011-12-02 20:24:49222 int exit_code;
[email protected]4967f792012-01-20 22:14:40223 process_->GetTerminationStatus(&exit_code);
[email protected]4cb43102011-12-02 20:24:49224 std::string message =
225 base::StringPrintf("NaCl process exited with status %i (0x%x)",
226 exit_code, exit_code);
227 if (exit_code == 0) {
228 LOG(INFO) << message;
229 } else {
230 LOG(ERROR) << message;
231 }
232
[email protected]c8e1ea32013-02-13 02:19:01233 if (internal_->socket_for_renderer != NACL_INVALID_HANDLE) {
234 if (NaClClose(internal_->socket_for_renderer) != 0) {
235 NOTREACHED() << "NaClClose() failed";
[email protected]909c2402011-05-09 11:39:04236 }
[email protected]c47ec402010-07-29 10:20:49237 }
[email protected]6294dd02013-01-09 17:27:23238
[email protected]c8e1ea32013-02-13 02:19:01239 if (internal_->socket_for_sel_ldr != NACL_INVALID_HANDLE) {
240 if (NaClClose(internal_->socket_for_sel_ldr) != 0) {
241 NOTREACHED() << "NaClClose() failed";
[email protected]909c2402011-05-09 11:39:04242 }
[email protected]c47ec402010-07-29 10:20:49243 }
244
[email protected]909c2402011-05-09 11:39:04245 if (reply_msg_) {
246 // The process failed to launch for some reason.
247 // Don't keep the renderer hanging.
248 reply_msg_->set_reply_error();
[email protected]01e59752013-06-18 00:17:35249 nacl_host_message_filter_->Send(reply_msg_);
[email protected]909c2402011-05-09 11:39:04250 }
[email protected]b39c6d92012-01-31 16:38:41251#if defined(OS_WIN)
[email protected]a575da52012-03-22 13:08:36252 if (process_launched_by_broker_) {
253 NaClBrokerService::GetInstance()->OnLoaderDied();
[email protected]5ca93be2012-03-21 20:04:06254 }
[email protected]b39c6d92012-01-31 16:38:41255#endif
[email protected]fb1277e82009-11-21 20:32:30256}
257
[email protected]773ebb92011-11-15 19:06:52258// This is called at browser startup.
259// static
260void NaClProcessHost::EarlyStartup() {
261#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
262 // Open the IRT file early to make sure that it isn't replaced out from
263 // under us by autoupdate.
264 NaClBrowser::GetInstance()->EnsureIrtAvailable();
265#endif
[email protected]9addd1c2012-09-15 14:28:24266 CommandLine* cmd = CommandLine::ForCurrentProcess();
267 UMA_HISTOGRAM_BOOLEAN(
268 "NaCl.nacl-gdb",
269 !cmd->GetSwitchValuePath(switches::kNaClGdb).empty());
270 UMA_HISTOGRAM_BOOLEAN(
271 "NaCl.nacl-gdb-script",
272 !cmd->GetSwitchValuePath(switches::kNaClGdbScript).empty());
273 UMA_HISTOGRAM_BOOLEAN(
274 "NaCl.enable-nacl-debug",
275 cmd->HasSwitch(switches::kEnableNaClDebug));
[email protected]66f409c2012-10-04 20:59:04276 NaClBrowser::GetInstance()->SetDebugPatterns(
277 cmd->GetSwitchValueASCII(switches::kNaClDebugMask));
[email protected]773ebb92011-11-15 19:06:52278}
279
[email protected]a575da52012-03-22 13:08:36280void NaClProcessHost::Launch(
[email protected]01e59752013-06-18 00:17:35281 NaClHostMessageFilter* nacl_host_message_filter,
[email protected]8f42b4d2012-03-24 14:12:33282 IPC::Message* reply_msg,
[email protected]3a0506cc2013-07-01 20:28:31283 const base::FilePath& manifest_path) {
[email protected]01e59752013-06-18 00:17:35284 nacl_host_message_filter_ = nacl_host_message_filter;
[email protected]a575da52012-03-22 13:08:36285 reply_msg_ = reply_msg;
[email protected]3a0506cc2013-07-01 20:28:31286 manifest_path_ = manifest_path;
[email protected]a575da52012-03-22 13:08:36287
[email protected]773ebb92011-11-15 19:06:52288 // Start getting the IRT open asynchronously while we launch the NaCl process.
[email protected]09afc2e2012-04-10 17:29:03289 // We'll make sure this actually finished in StartWithLaunchedProcess, below.
[email protected]e97990f2012-05-15 22:06:06290 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
291 nacl_browser->EnsureAllResourcesAvailable();
292 if (!nacl_browser->IsOk()) {
[email protected]ec7540f2013-01-17 00:00:35293 LOG(ERROR) << "NaCl process launch failed: could not find all the "
294 "resources needed to launch the process";
[email protected]a575da52012-03-22 13:08:36295 delete this;
296 return;
[email protected]773ebb92011-11-15 19:06:52297 }
298
[email protected]c47ec402010-07-29 10:20:49299 // Rather than creating a socket pair in the renderer, and passing
300 // one side through the browser to sel_ldr, socket pairs are created
301 // in the browser and then passed to the renderer and sel_ldr.
302 //
303 // This is mainly for the benefit of Windows, where sockets cannot
304 // be passed in messages, but are copied via DuplicateHandle().
305 // This means the sandboxed renderer cannot send handles to the
306 // browser process.
307
[email protected]c8e1ea32013-02-13 02:19:01308 NaClHandle pair[2];
[email protected]6294dd02013-01-09 17:27:23309 // Create a connected socket
[email protected]c8e1ea32013-02-13 02:19:01310 if (NaClSocketPair(pair) == -1) {
[email protected]ec7540f2013-01-17 00:00:35311 LOG(ERROR) << "NaCl process launch failed: could not create a socket pair";
[email protected]6294dd02013-01-09 17:27:23312 delete this;
313 return;
[email protected]c47ec402010-07-29 10:20:49314 }
[email protected]6294dd02013-01-09 17:27:23315 internal_->socket_for_renderer = pair[0];
316 internal_->socket_for_sel_ldr = pair[1];
317 SetCloseOnExec(pair[0]);
318 SetCloseOnExec(pair[1]);
[email protected]d032f492009-09-29 00:33:46319
320 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30321 if (!LaunchSelLdr()) {
[email protected]a575da52012-03-22 13:08:36322 delete this;
[email protected]d032f492009-09-29 00:33:46323 }
[email protected]d032f492009-09-29 00:33:46324}
[email protected]646e15552012-04-06 22:01:04325
[email protected]646e15552012-04-06 22:01:04326void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
[email protected]82d17502012-05-23 19:12:40327 if (!CommandLine::ForCurrentProcess()->GetSwitchValuePath(
328 switches::kNaClGdb).empty()) {
[email protected]04284252013-06-11 22:30:14329 LaunchNaClGdb();
[email protected]646e15552012-04-06 22:01:04330 }
[email protected]646e15552012-04-06 22:01:04331}
[email protected]646e15552012-04-06 22:01:04332
333#if defined(OS_WIN)
334void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
335 process_launched_by_broker_ = true;
336 process_->SetHandle(handle);
[email protected]09afc2e2012-04-10 17:29:03337 if (!StartWithLaunchedProcess())
338 delete this;
[email protected]646e15552012-04-06 22:01:04339}
340
[email protected]ea6588842012-05-03 05:39:38341void NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker(bool success) {
342 IPC::Message* reply = attach_debug_exception_handler_reply_msg_.release();
343 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply, success);
344 Send(reply);
[email protected]646e15552012-04-06 22:01:04345}
346#endif
347
348// Needed to handle sync messages in OnMessageRecieved.
349bool NaClProcessHost::Send(IPC::Message* msg) {
350 return process_->Send(msg);
351}
352
[email protected]04284252013-06-11 22:30:14353bool NaClProcessHost::LaunchNaClGdb() {
[email protected]646e15552012-04-06 22:01:04354#if defined(OS_WIN)
[email protected]04284252013-06-11 22:30:14355 base::FilePath nacl_gdb =
356 CommandLine::ForCurrentProcess()->GetSwitchValuePath(switches::kNaClGdb);
357 CommandLine cmd_line(nacl_gdb);
358#else
[email protected]5b974952012-04-05 18:18:23359 CommandLine::StringType nacl_gdb =
360 CommandLine::ForCurrentProcess()->GetSwitchValueNative(
361 switches::kNaClGdb);
362 CommandLine::StringVector argv;
363 // We don't support spaces inside arguments in --nacl-gdb switch.
364 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
365 CommandLine cmd_line(argv);
[email protected]04284252013-06-11 22:30:14366#endif
[email protected]5b974952012-04-05 18:18:23367 cmd_line.AppendArg("--eval-command");
[email protected]04284252013-06-11 22:30:14368 base::FilePath::StringType irt_path(
369 NaClBrowser::GetInstance()->GetIrtFilePath().value());
370 // Avoid back slashes because nacl-gdb uses posix escaping rules on Windows.
371 // See issue https://code.google.com/p/nativeclient/issues/detail?id=3482.
372 std::replace(irt_path.begin(), irt_path.end(), '\\', '/');
373 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt \"") + irt_path +
374 FILE_PATH_LITERAL("\""));
[email protected]3a0506cc2013-07-01 20:28:31375 if (!manifest_path_.empty()) {
[email protected]5b974952012-04-05 18:18:23376 cmd_line.AppendArg("--eval-command");
[email protected]3a0506cc2013-07-01 20:28:31377 base::FilePath::StringType manifest_path_value(manifest_path_.value());
[email protected]04284252013-06-11 22:30:14378 std::replace(manifest_path_value.begin(), manifest_path_value.end(),
379 '\\', '/');
380 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest \"") +
381 manifest_path_value + FILE_PATH_LITERAL("\""));
[email protected]5b974952012-04-05 18:18:23382 }
383 cmd_line.AppendArg("--eval-command");
[email protected]04284252013-06-11 22:30:14384 cmd_line.AppendArg("target remote :4014");
[email protected]650b2d52013-02-10 03:41:45385 base::FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
[email protected]401b90792012-05-30 11:41:13386 switches::kNaClGdbScript);
387 if (!script.empty()) {
388 cmd_line.AppendArg("--command");
389 cmd_line.AppendArgNative(script.value());
390 }
[email protected]5b974952012-04-05 18:18:23391 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
392}
393
[email protected]fb1277e82009-11-21 20:32:30394bool NaClProcessHost::LaunchSelLdr() {
[email protected]4967f792012-01-20 22:14:40395 std::string channel_id = process_->GetHost()->CreateChannel();
[email protected]ec7540f2013-01-17 00:00:35396 if (channel_id.empty()) {
397 LOG(ERROR) << "NaCl process launch failed: could not create channel";
[email protected]d032f492009-09-29 00:33:46398 return false;
[email protected]ec7540f2013-01-17 00:00:35399 }
[email protected]d032f492009-09-29 00:33:46400
[email protected]e3fc75a2011-05-05 08:20:42401 CommandLine::StringType nacl_loader_prefix;
402#if defined(OS_POSIX)
403 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
404 switches::kNaClLoaderCmdPrefix);
405#endif // defined(OS_POSIX)
406
[email protected]d032f492009-09-29 00:33:46407 // Build command line for nacl.
[email protected]8c40f322011-08-24 03:33:36408
409#if defined(OS_MACOSX)
410 // The Native Client process needs to be able to allocate a 1GB contiguous
411 // region to use as the client environment's virtual address space. ASLR
412 // (PIE) interferes with this by making it possible that no gap large enough
413 // to accomodate this request will exist in the child process' address
414 // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
415 // http://code.google.com/p/nativeclient/issues/detail?id=2043.
[email protected]4cb43102011-12-02 20:24:49416 int flags = ChildProcessHost::CHILD_NO_PIE;
[email protected]8c40f322011-08-24 03:33:36417#elif defined(OS_LINUX)
[email protected]4cb43102011-12-02 20:24:49418 int flags = nacl_loader_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
419 ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36420#else
[email protected]4cb43102011-12-02 20:24:49421 int flags = ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36422#endif
423
[email protected]650b2d52013-02-10 03:41:45424 base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
[email protected]fb1277e82009-11-21 20:32:30425 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46426 return false;
427
[email protected]31a665e72012-03-11 12:37:46428#if defined(OS_WIN)
429 // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
430 if (RunningOnWOW64()) {
[email protected]e804b532013-06-21 14:20:36431 if (!NaClBrowser::GetInstance()->GetNaCl64ExePath(&exe_path)) {
[email protected]31a665e72012-03-11 12:37:46432 return false;
[email protected]ec7540f2013-01-17 00:00:35433 }
[email protected]31a665e72012-03-11 12:37:46434 }
435#endif
436
[email protected]33a05af2012-03-02 18:15:51437 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
438 nacl::CopyNaClCommandLineArguments(cmd_line.get());
[email protected]599e6642010-01-27 18:52:13439
[email protected]05076ba22010-07-30 05:59:57440 cmd_line->AppendSwitchASCII(switches::kProcessType,
441 switches::kNaClLoaderProcess);
[email protected]4734d0b2011-12-03 07:10:44442 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
[email protected]93156cec2011-09-12 21:14:44443 if (logging::DialogsAreSuppressed())
444 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
[email protected]d032f492009-09-29 00:33:46445
[email protected]e3fc75a2011-05-05 08:20:42446 if (!nacl_loader_prefix.empty())
447 cmd_line->PrependWrapper(nacl_loader_prefix);
448
[email protected]103607e2010-02-01 18:57:09449 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46450#if defined(OS_WIN)
[email protected]773ebb92011-11-15 19:06:52451 if (RunningOnWOW64()) {
[email protected]ec7540f2013-01-17 00:00:35452 if (!NaClBrokerService::GetInstance()->LaunchLoader(
453 weak_factory_.GetWeakPtr(), channel_id)) {
454 LOG(ERROR) << "NaCl process launch failed: broker service did not launch "
455 "process";
456 return false;
457 }
[email protected]4bdde602010-06-16 03:17:35458 } else {
[email protected]34f48682013-03-20 00:30:18459 process_->Launch(new NaClSandboxedProcessLauncherDelegate,
460 cmd_line.release());
[email protected]4bdde602010-06-16 03:17:35461 }
[email protected]103607e2010-02-01 18:57:09462#elif defined(OS_POSIX)
[email protected]4967f792012-01-20 22:14:40463 process_->Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]a82af392012-02-24 04:40:20464 base::EnvironmentVector(),
[email protected]33a05af2012-03-02 18:15:51465 cmd_line.release());
[email protected]103607e2010-02-01 18:57:09466#endif
[email protected]d032f492009-09-29 00:33:46467
[email protected]fb1277e82009-11-21 20:32:30468 return true;
[email protected]d032f492009-09-29 00:33:46469}
470
[email protected]646e15552012-04-06 22:01:04471bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
472 bool handled = true;
473 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
474 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
475 OnQueryKnownToValidate)
476 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
477 OnSetKnownToValidate)
[email protected]041834522013-05-29 00:19:27478 IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_ResolveFileToken,
479 OnResolveFileToken)
[email protected]ea6588842012-05-03 05:39:38480#if defined(OS_WIN)
481 IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_AttachDebugExceptionHandler,
482 OnAttachDebugExceptionHandler)
483#endif
[email protected]17b5a8172012-06-22 21:09:09484 IPC_MESSAGE_HANDLER(NaClProcessHostMsg_PpapiChannelCreated,
485 OnPpapiChannelCreated)
[email protected]646e15552012-04-06 22:01:04486 IPC_MESSAGE_UNHANDLED(handled = false)
487 IPC_END_MESSAGE_MAP()
488 return handled;
[email protected]103607e2010-02-01 18:57:09489}
490
[email protected]773ebb92011-11-15 19:06:52491void NaClProcessHost::OnProcessLaunched() {
[email protected]09afc2e2012-04-10 17:29:03492 if (!StartWithLaunchedProcess())
493 delete this;
[email protected]773ebb92011-11-15 19:06:52494}
495
[email protected]e97990f2012-05-15 22:06:06496// Called when the NaClBrowser singleton has been fully initialized.
497void NaClProcessHost::OnResourcesReady() {
[email protected]773ebb92011-11-15 19:06:52498 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]ec7540f2013-01-17 00:00:35499 if (!nacl_browser->IsReady()) {
500 LOG(ERROR) << "NaCl process launch failed: could not acquire shared "
501 "resources needed by NaCl";
502 delete this;
503 } else if (!SendStart()) {
[email protected]338466a82011-05-03 04:27:43504 delete this;
505 }
506}
507
[email protected]17b5a8172012-06-22 21:09:09508bool NaClProcessHost::ReplyToRenderer(
509 const IPC::ChannelHandle& channel_handle) {
[email protected]6294dd02013-01-09 17:27:23510 nacl::FileDescriptor handle_for_renderer;
[email protected]c47ec402010-07-29 10:20:49511#if defined(OS_WIN)
[email protected]6294dd02013-01-09 17:27:23512 // Copy the handle into the renderer process.
513 HANDLE handle_in_renderer;
514 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
515 reinterpret_cast<HANDLE>(
516 internal_->socket_for_renderer),
[email protected]01e59752013-06-18 00:17:35517 nacl_host_message_filter_->peer_handle(),
[email protected]6294dd02013-01-09 17:27:23518 &handle_in_renderer,
519 0, // Unused given DUPLICATE_SAME_ACCESS.
520 FALSE,
521 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
[email protected]ec7540f2013-01-17 00:00:35522 LOG(ERROR) << "DuplicateHandle() failed";
[email protected]6294dd02013-01-09 17:27:23523 return false;
[email protected]c47ec402010-07-29 10:20:49524 }
[email protected]6294dd02013-01-09 17:27:23525 handle_for_renderer = reinterpret_cast<nacl::FileDescriptor>(
526 handle_in_renderer);
527#else
528 // No need to dup the imc_handle - we don't pass it anywhere else so
529 // it cannot be closed.
530 nacl::FileDescriptor imc_handle;
531 imc_handle.fd = internal_->socket_for_renderer;
532 imc_handle.auto_close = true;
533 handle_for_renderer = imc_handle;
534#endif
[email protected]c47ec402010-07-29 10:20:49535
536#if defined(OS_WIN)
[email protected]e4f6eb0232012-04-17 00:47:50537 // If we are on 64-bit Windows, the NaCl process's sandbox is
538 // managed by a different process from the renderer's sandbox. We
539 // need to inform the renderer's sandbox about the NaCl process so
540 // that the renderer can send handles to the NaCl process using
541 // BrokerDuplicateHandle().
542 if (RunningOnWOW64()) {
[email protected]171fa98d2012-04-23 21:34:01543 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
[email protected]ec7540f2013-01-17 00:00:35544 LOG(ERROR) << "Failed to add NaCl process PID";
[email protected]e4f6eb0232012-04-17 00:47:50545 return false;
546 }
547 }
[email protected]fb1277e82009-11-21 20:32:30548#endif
549
[email protected]108fd342013-01-04 20:46:54550 const ChildProcessData& data = process_->GetData();
[email protected]01e59752013-06-18 00:17:35551 NaClHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]6294dd02013-01-09 17:27:23552 reply_msg_, handle_for_renderer,
[email protected]108fd342013-01-04 20:46:54553 channel_handle, base::GetProcId(data.handle), data.id);
[email protected]01e59752013-06-18 00:17:35554 nacl_host_message_filter_->Send(reply_msg_);
555 nacl_host_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30556 reply_msg_ = NULL;
[email protected]c8e1ea32013-02-13 02:19:01557 internal_->socket_for_renderer = NACL_INVALID_HANDLE;
[email protected]00d99542012-04-17 22:48:02558 return true;
559}
[email protected]fb1277e82009-11-21 20:32:30560
[email protected]d571c032012-09-14 12:39:18561// TCP port we chose for NaCl debug stub. It can be any other number.
562static const int kDebugStubPort = 4014;
563
564#if defined(OS_POSIX)
565SocketDescriptor NaClProcessHost::GetDebugStubSocketHandle() {
[email protected]13cad0b2012-12-07 17:57:34566 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
567 SocketDescriptor s;
568 // We allocate currently unused TCP port for debug stub tests. The port
569 // number is passed to the test via debug stub port listener.
570 if (nacl_browser->HasGdbDebugStubPortListener()) {
571 int port;
572 s = net::TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port);
573 if (s != net::TCPListenSocket::kInvalidSocket) {
574 nacl_browser->FireGdbDebugStubPortOpened(port);
575 }
576 } else {
577 s = net::TCPListenSocket::CreateAndBind("127.0.0.1", kDebugStubPort);
578 }
579 if (s == net::TCPListenSocket::kInvalidSocket) {
580 LOG(ERROR) << "failed to open socket for debug stub";
581 return net::TCPListenSocket::kInvalidSocket;
582 }
[email protected]d571c032012-09-14 12:39:18583 if (listen(s, 1)) {
584 LOG(ERROR) << "listen() failed on debug stub socket";
[email protected]13cad0b2012-12-07 17:57:34585 if (HANDLE_EINTR(close(s)) < 0)
586 PLOG(ERROR) << "failed to close debug stub socket";
[email protected]d571c032012-09-14 12:39:18587 return net::TCPListenSocket::kInvalidSocket;
588 }
589 return s;
590}
591#endif
592
[email protected]00d99542012-04-17 22:48:02593bool NaClProcessHost::StartNaClExecution() {
594 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
595
596 nacl::NaClStartParams params;
[email protected]8c670832012-05-26 04:30:12597 params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
598 params.validation_cache_key = nacl_browser->GetValidationCacheKey();
[email protected]00d99542012-04-17 22:48:02599 params.version = chrome::VersionInfo().CreateVersionString();
600 params.enable_exception_handling = enable_exception_handling_;
[email protected]66f409c2012-10-04 20:59:04601 params.enable_debug_stub = enable_debug_stub_ &&
602 NaClBrowser::GetInstance()->URLMatchesDebugPatterns(manifest_url_);
[email protected]7522077b2013-01-17 23:39:40603 // Enable PPAPI proxy channel creation only for renderer processes.
604 params.enable_ipc_proxy = enable_ppapi_proxy();
[email protected]2e1e6f02013-01-11 18:22:56605 params.uses_irt = uses_irt_;
[email protected]be524622013-04-23 00:12:19606 params.enable_dyncode_syscalls = enable_dyncode_syscalls_;
[email protected]00d99542012-04-17 22:48:02607
608 const ChildProcessData& data = process_->GetData();
[email protected]6294dd02013-01-09 17:27:23609 if (!ShareHandleToSelLdr(data.handle,
610 internal_->socket_for_sel_ldr, true,
611 &params.handles)) {
612 return false;
[email protected]773ebb92011-11-15 19:06:52613 }
614
[email protected]2e1e6f02013-01-11 18:22:56615 if (params.uses_irt) {
616 base::PlatformFile irt_file = nacl_browser->IrtFile();
617 CHECK_NE(irt_file, base::kInvalidPlatformFileValue);
[email protected]2e1e6f02013-01-11 18:22:56618 // Send over the IRT file handle. We don't close our own copy!
619 if (!ShareHandleToSelLdr(data.handle, irt_file, false, &params.handles))
620 return false;
621 }
[email protected]c47ec402010-07-29 10:20:49622
[email protected]ab88d1542011-11-18 22:52:00623#if defined(OS_MACOSX)
624 // For dynamic loading support, NaCl requires a file descriptor that
625 // was created in /tmp, since those created with shm_open() are not
626 // mappable with PROT_EXEC. Rather than requiring an extra IPC
627 // round trip out of the sandbox, we create an FD here.
[email protected]cbbe7842011-11-17 22:01:25628 base::SharedMemory memory_buffer;
[email protected]b05df6b2011-12-01 23:19:31629 base::SharedMemoryCreateOptions options;
630 options.size = 1;
631 options.executable = true;
632 if (!memory_buffer.Create(options)) {
[email protected]09afc2e2012-04-10 17:29:03633 DLOG(ERROR) << "Failed to allocate memory buffer";
634 return false;
[email protected]2c68bf032010-11-11 23:16:30635 }
[email protected]cbbe7842011-11-17 22:01:25636 nacl::FileDescriptor memory_fd;
637 memory_fd.fd = dup(memory_buffer.handle().fd);
638 if (memory_fd.fd < 0) {
[email protected]09afc2e2012-04-10 17:29:03639 DLOG(ERROR) << "Failed to dup() a file descriptor";
640 return false;
[email protected]cbbe7842011-11-17 22:01:25641 }
642 memory_fd.auto_close = true;
[email protected]00d99542012-04-17 22:48:02643 params.handles.push_back(memory_fd);
[email protected]2c68bf032010-11-11 23:16:30644#endif
645
[email protected]d571c032012-09-14 12:39:18646#if defined(OS_POSIX)
[email protected]ed637bb2012-10-15 17:36:05647 if (params.enable_debug_stub) {
[email protected]d571c032012-09-14 12:39:18648 SocketDescriptor server_bound_socket = GetDebugStubSocketHandle();
649 if (server_bound_socket != net::TCPListenSocket::kInvalidSocket) {
650 params.debug_stub_server_bound_socket =
651 nacl::FileDescriptor(server_bound_socket, true);
652 }
653 }
654#endif
655
[email protected]ea6588842012-05-03 05:39:38656 process_->Send(new NaClProcessMsg_Start(params));
[email protected]b39c6d92012-01-31 16:38:41657
[email protected]c8e1ea32013-02-13 02:19:01658 internal_->socket_for_sel_ldr = NACL_INVALID_HANDLE;
[email protected]09afc2e2012-04-10 17:29:03659 return true;
660}
661
[email protected]00d99542012-04-17 22:48:02662bool NaClProcessHost::SendStart() {
[email protected]7522077b2013-01-17 23:39:40663 if (!enable_ppapi_proxy()) {
[email protected]17b5a8172012-06-22 21:09:09664 if (!ReplyToRenderer(IPC::ChannelHandle()))
665 return false;
666 }
667 return StartNaClExecution();
668}
669
[email protected]8510d282012-08-30 19:47:38670// This method is called when NaClProcessHostMsg_PpapiChannelCreated is
671// received or PpapiHostMsg_ChannelCreated is forwarded by our plugin
672// listener.
[email protected]17b5a8172012-06-22 21:09:09673void NaClProcessHost::OnPpapiChannelCreated(
674 const IPC::ChannelHandle& channel_handle) {
[email protected]7522077b2013-01-17 23:39:40675 // Only renderer processes should create a channel.
676 DCHECK(enable_ppapi_proxy());
[email protected]8510d282012-08-30 19:47:38677 // If the proxy channel is null, this must be the initial NaCl-Browser IPC
678 // channel.
679 if (!ipc_proxy_channel_.get()) {
[email protected]f3b357692013-03-22 05:16:13680 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
[email protected]9e141212013-01-21 15:21:56681
[email protected]8510d282012-08-30 19:47:38682 ipc_proxy_channel_.reset(
683 new IPC::ChannelProxy(channel_handle,
684 IPC::Channel::MODE_CLIENT,
685 &ipc_plugin_listener_,
[email protected]cadac622013-06-11 16:46:36686 base::MessageLoopProxy::current().get()));
[email protected]0c7193742012-11-07 19:05:03687 // Create the browser ppapi host and enable PPAPI message dispatching to the
688 // browser process.
[email protected]adf7cd52012-12-04 19:37:46689 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
[email protected]9e141212013-01-21 15:21:56690 ipc_proxy_channel_.get(), // sender
[email protected]0c7193742012-11-07 19:05:03691 permissions_,
692 process_->GetData().handle,
[email protected]b4b53d182012-09-12 02:56:55693 ipc_proxy_channel_.get(),
[email protected]01e59752013-06-18 00:17:35694 nacl_host_message_filter_->GetHostResolver(),
695 nacl_host_message_filter_->render_process_id(),
[email protected]7bb5d2c2013-04-29 22:33:49696 render_view_id_,
697 profile_directory_));
[email protected]adf7cd52012-12-04 19:37:46698
[email protected]ac07ec52013-04-22 17:32:45699 ppapi::PpapiNaClChannelArgs args;
[email protected]01e59752013-06-18 00:17:35700 args.off_the_record = nacl_host_message_filter_->off_the_record();
[email protected]ac07ec52013-04-22 17:32:45701 args.permissions = permissions_;
702 CommandLine* cmdline = CommandLine::ForCurrentProcess();
703 DCHECK(cmdline);
704 std::string flag_whitelist[] = {switches::kV, switches::kVModule};
705 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
706 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
707 if (!value.empty()) {
708 args.switch_names.push_back(flag_whitelist[i]);
709 args.switch_values.push_back(value);
710 }
711 }
712
[email protected]4b30e7d2013-04-24 23:52:14713 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
714 scoped_ptr<ppapi::host::HostFactory>(
715 new chrome::ChromeBrowserPepperHostFactory(ppapi_host_.get())));
716
[email protected]8510d282012-08-30 19:47:38717 // Send a message to create the NaCl-Renderer channel. The handle is just
718 // a place holder.
719 ipc_proxy_channel_->Send(
720 new PpapiMsg_CreateNaClChannel(
[email protected]01e59752013-06-18 00:17:35721 nacl_host_message_filter_->render_process_id(),
[email protected]ac07ec52013-04-22 17:32:45722 args,
[email protected]8510d282012-08-30 19:47:38723 SerializedHandle(SerializedHandle::CHANNEL_HANDLE,
724 IPC::InvalidPlatformFileForTransit())));
725 } else if (reply_msg_) {
726 // Otherwise, this must be a renderer channel.
727 ReplyToRenderer(channel_handle);
728 } else {
729 // Attempt to open more than 1 renderer channel is not supported.
730 // Shut down the NaCl process.
731 process_->GetHost()->ForceShutdown();
732 }
733}
734
735bool NaClProcessHost::OnUntrustedMessageForwarded(const IPC::Message& msg) {
736 // Handle messages that have been forwarded from our PluginListener.
737 // These messages come from untrusted code so should be handled with care.
738 bool handled = true;
739 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
740 IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated,
741 OnPpapiChannelCreated)
742 IPC_MESSAGE_UNHANDLED(handled = false)
743 IPC_END_MESSAGE_MAP()
744 return handled;
[email protected]00d99542012-04-17 22:48:02745}
746
[email protected]09afc2e2012-04-10 17:29:03747bool NaClProcessHost::StartWithLaunchedProcess() {
[email protected]09afc2e2012-04-10 17:29:03748 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]09afc2e2012-04-10 17:29:03749
[email protected]e97990f2012-05-15 22:06:06750 if (nacl_browser->IsReady()) {
751 return SendStart();
752 } else if (nacl_browser->IsOk()) {
753 nacl_browser->WaitForResources(
754 base::Bind(&NaClProcessHost::OnResourcesReady,
755 weak_factory_.GetWeakPtr()));
756 return true;
757 } else {
[email protected]ec7540f2013-01-17 00:00:35758 LOG(ERROR) << "NaCl process failed to launch: previously failed to acquire "
759 "shared resources";
[email protected]e97990f2012-05-15 22:06:06760 return false;
761 }
[email protected]d032f492009-09-29 00:33:46762}
763
[email protected]4a0141b2012-03-27 01:15:30764void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
765 bool* result) {
[email protected]7cfaf982012-05-09 18:37:47766 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]57473ebc2012-05-30 07:44:52767 *result = nacl_browser->QueryKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30768}
769
770void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
[email protected]57473ebc2012-05-30 07:44:52771 NaClBrowser::GetInstance()->SetKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30772}
[email protected]ea6588842012-05-03 05:39:38773
[email protected]041834522013-05-29 00:19:27774void NaClProcessHost::FileResolved(
775 base::PlatformFile* file,
776 const base::FilePath& file_path,
777 IPC::Message* reply_msg) {
778 if (*file != base::kInvalidPlatformFileValue) {
779 IPC::PlatformFileForTransit handle = IPC::GetFileHandleForProcess(
780 *file,
781 process_->GetData().handle,
782 true /* close_source */);
783 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
784 reply_msg,
785 handle,
786 file_path);
787 } else {
788 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
789 reply_msg,
790 IPC::InvalidPlatformFileForTransit(),
791 base::FilePath(FILE_PATH_LITERAL("")));
792 }
793 Send(reply_msg);
794}
795
796void NaClProcessHost::OnResolveFileToken(uint64 file_token_lo,
797 uint64 file_token_hi,
798 IPC::Message* reply_msg) {
799 // Was the file registered?
800 //
801 // Note that the file path cache is of bounded size, and old entries can get
802 // evicted. If a large number of NaCl modules are being launched at once,
803 // resolving the file_token may fail because the path cache was thrashed
804 // while the file_token was in flight. In this case the query fails, and we
805 // need to fall back to the slower path.
806 //
807 // However: each NaCl process will consume 2-3 entries as it starts up, this
808 // means that eviction will not happen unless you start up 33+ NaCl processes
809 // at the same time, and this still requires worst-case timing. As a
810 // practical matter, no entries should be evicted prematurely.
811 // The cache itself should take ~ (150 characters * 2 bytes/char + ~60 bytes
812 // data structure overhead) * 100 = 35k when full, so making it bigger should
813 // not be a problem, if needed.
814 //
815 // Each NaCl process will consume 2-3 entries because the manifest and main
816 // nexe are currently not resolved. Shared libraries will be resolved. They
817 // will be loaded sequentially, so they will only consume a single entry
818 // while the load is in flight.
819 //
820 // TODO(ncbray): track behavior with UMA. If entries are getting evicted or
821 // bogus keys are getting queried, this would be good to know.
822 base::FilePath file_path;
823 if (!NaClBrowser::GetInstance()->GetFilePath(file_token_lo, file_token_hi,
824 &file_path)) {
825 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
826 reply_msg,
827 IPC::InvalidPlatformFileForTransit(),
828 base::FilePath(FILE_PATH_LITERAL("")));
829 Send(reply_msg);
830 return;
831 }
832
833 // Scratch space to share between the callbacks.
834 base::PlatformFile* data = new base::PlatformFile();
835
836 // Open the file.
837 if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
838 FROM_HERE,
839 base::Bind(nacl::OpenNaClExecutableImpl,
840 file_path, data),
841 base::Bind(&NaClProcessHost::FileResolved,
842 weak_factory_.GetWeakPtr(),
843 base::Owned(data),
844 file_path,
845 reply_msg))) {
846 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
847 reply_msg,
848 IPC::InvalidPlatformFileForTransit(),
849 base::FilePath(FILE_PATH_LITERAL("")));
850 Send(reply_msg);
851 }
852}
853
[email protected]ea6588842012-05-03 05:39:38854#if defined(OS_WIN)
855void NaClProcessHost::OnAttachDebugExceptionHandler(const std::string& info,
856 IPC::Message* reply_msg) {
857 if (!AttachDebugExceptionHandler(info, reply_msg)) {
858 // Send failure message.
859 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply_msg,
860 false);
861 Send(reply_msg);
862 }
863}
864
865bool NaClProcessHost::AttachDebugExceptionHandler(const std::string& info,
866 IPC::Message* reply_msg) {
[email protected]2c227ff2012-08-11 00:51:32867 if (!enable_exception_handling_ && !enable_debug_stub_) {
[email protected]ea6588842012-05-03 05:39:38868 DLOG(ERROR) <<
[email protected]2c227ff2012-08-11 00:51:32869 "Debug exception handler requested by NaCl process when not enabled";
[email protected]ea6588842012-05-03 05:39:38870 return false;
871 }
872 if (debug_exception_handler_requested_) {
873 // The NaCl process should not request this multiple times.
874 DLOG(ERROR) << "Multiple AttachDebugExceptionHandler requests received";
875 return false;
876 }
877 debug_exception_handler_requested_ = true;
878
879 base::ProcessId nacl_pid = base::GetProcId(process_->GetData().handle);
880 base::win::ScopedHandle process_handle;
881 // We cannot use process_->GetData().handle because it does not have
882 // the necessary access rights. We open the new handle here rather
883 // than in the NaCl broker process in case the NaCl loader process
884 // dies before the NaCl broker process receives the message we send.
885 // The debug exception handler uses DebugActiveProcess() to attach,
886 // but this takes a PID. We need to prevent the NaCl loader's PID
887 // from being reused before DebugActiveProcess() is called, and
888 // holding a process handle open achieves this.
889 if (!base::OpenProcessHandleWithAccess(
890 nacl_pid,
891 base::kProcessAccessQueryInformation |
892 base::kProcessAccessSuspendResume |
893 base::kProcessAccessTerminate |
894 base::kProcessAccessVMOperation |
895 base::kProcessAccessVMRead |
896 base::kProcessAccessVMWrite |
[email protected]29172322013-01-10 17:35:16897 base::kProcessAccessDuplicateHandle |
[email protected]ea6588842012-05-03 05:39:38898 base::kProcessAccessWaitForTermination,
899 process_handle.Receive())) {
900 LOG(ERROR) << "Failed to get process handle";
901 return false;
902 }
903
904 attach_debug_exception_handler_reply_msg_.reset(reply_msg);
905 // If the NaCl loader is 64-bit, the process running its debug
906 // exception handler must be 64-bit too, so we use the 64-bit NaCl
907 // broker process for this. Otherwise, on a 32-bit system, we use
908 // the 32-bit browser process to run the debug exception handler.
909 if (RunningOnWOW64()) {
910 return NaClBrokerService::GetInstance()->LaunchDebugExceptionHandler(
[email protected]fd37bf62012-05-04 16:46:48911 weak_factory_.GetWeakPtr(), nacl_pid, process_handle, info);
[email protected]ea6588842012-05-03 05:39:38912 } else {
913 NaClStartDebugExceptionHandlerThread(
[email protected]fd37bf62012-05-04 16:46:48914 process_handle.Take(), info,
[email protected]ea6588842012-05-03 05:39:38915 base::MessageLoopProxy::current(),
916 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
917 weak_factory_.GetWeakPtr()));
918 return true;
919 }
920}
921#endif