blob: 9c9f1af0cf3afe7a647b3617662e0122dfabb31a [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]ac07ec52013-04-22 17:32:4510#include "base/base_switches.h"
[email protected]30c1eea2011-10-17 18:40:3011#include "base/bind.h"
[email protected]103607e2010-02-01 18:57:0912#include "base/command_line.h"
[email protected]6d7f55f2013-05-14 10:12:5613#include "base/file_util.h"
[email protected]5b974952012-04-05 18:18:2314#include "base/message_loop.h"
[email protected]9addd1c2012-09-15 14:28:2415#include "base/metrics/histogram.h"
[email protected]338466a82011-05-03 04:27:4316#include "base/path_service.h"
[email protected]108fd342013-01-04 20:46:5417#include "base/process_util.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]3ea1b182013-02-08 22:38:4120#include "base/strings/string_number_conversions.h"
[email protected]1988e1c2013-02-28 20:27:4221#include "base/strings/string_split.h"
[email protected]112158af2013-06-07 23:46:1822#include "base/strings/utf_string_conversions.h"
[email protected]1e67c2b2011-03-04 01:17:3723#include "base/win/windows_version.h"
[email protected]a82af392012-02-24 04:40:2024#include "build/build_config.h"
[email protected]8f42b4d2012-03-24 14:12:3325#include "chrome/browser/extensions/extension_info_map.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]4b30e7d2013-04-24 23:52:1428#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
[email protected]31a665e72012-03-11 12:37:4629#include "chrome/common/chrome_constants.h"
[email protected]338466a82011-05-03 04:27:4330#include "chrome/common/chrome_paths.h"
[email protected]f3b357692013-03-22 05:16:1331#include "chrome/common/chrome_process_type.h"
[email protected]d032f492009-09-29 00:33:4632#include "chrome/common/chrome_switches.h"
[email protected]1657e6d2012-03-30 20:28:0033#include "chrome/common/chrome_version_info.h"
[email protected]d032f492009-09-29 00:33:4634#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0935#include "chrome/common/nacl_cmd_line.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]4967f792012-01-20 22:14:4038#include "content/public/browser/browser_child_process_host.h"
[email protected]0c7193742012-11-07 19:05:0339#include "content/public/browser/browser_ppapi_host.h"
[email protected]4967f792012-01-20 22:14:4040#include "content/public/browser/child_process_data.h"
[email protected]4734d0b2011-12-03 07:10:4441#include "content/public/common/child_process_host.h"
[email protected]9e141212013-01-21 15:21:5642#include "content/public/common/process_type.h"
[email protected]885c0e92012-11-13 20:27:4243#include "extensions/common/constants.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]7bb5d2c2013-04-29 22:33:49186 bool off_the_record,
187 const base::FilePath& profile_directory)
[email protected]87f35592012-04-08 00:49:16188 : manifest_url_(manifest_url),
[email protected]27b04df2012-12-10 23:43:10189 permissions_(GetNaClPermissions(permission_bits)),
[email protected]a575da52012-03-22 13:08:36190#if defined(OS_WIN)
191 process_launched_by_broker_(false),
[email protected]5b974952012-04-05 18:18:23192#elif defined(OS_LINUX)
193 wait_for_nacl_gdb_(false),
[email protected]a575da52012-03-22 13:08:36194#endif
195 reply_msg_(NULL),
[email protected]ea6588842012-05-03 05:39:38196#if defined(OS_WIN)
197 debug_exception_handler_requested_(false),
198#endif
[email protected]1d8a3d1f2011-02-19 07:11:52199 internal_(new NaClInternal()),
[email protected]9c009092013-05-01 03:14:09200 weak_factory_(this),
[email protected]d4062452013-04-17 05:08:35201 enable_exception_handling_(true),
[email protected]2c227ff2012-08-11 00:51:32202 enable_debug_stub_(false),
[email protected]2e1e6f02013-01-11 18:22:56203 uses_irt_(uses_irt),
[email protected]be524622013-04-23 00:12:19204 enable_dyncode_syscalls_(enable_dyncode_syscalls),
[email protected]8510d282012-08-30 19:47:38205 off_the_record_(off_the_record),
[email protected]7bb5d2c2013-04-29 22:33:49206 profile_directory_(profile_directory),
[email protected]9c009092013-05-01 03:14:09207 ipc_plugin_listener_(this),
[email protected]e02ff722012-11-06 03:53:06208 render_view_id_(render_view_id) {
[email protected]4967f792012-01-20 22:14:40209 process_.reset(content::BrowserChildProcessHost::Create(
[email protected]f3b357692013-03-22 05:16:13210 PROCESS_TYPE_NACL_LOADER, this));
[email protected]87f35592012-04-08 00:49:16211
212 // Set the display name so the user knows what plugin the process is running.
213 // We aren't on the UI thread so getting the pref locale for language
214 // formatting isn't possible, so IDN will be lost, but this is probably OK
215 // for this use case.
216 process_->SetName(net::FormatUrl(manifest_url_, std::string()));
[email protected]5ca93be2012-03-21 20:04:06217
[email protected]2c227ff2012-08-11 00:51:32218 enable_debug_stub_ = CommandLine::ForCurrentProcess()->HasSwitch(
219 switches::kEnableNaClDebug);
[email protected]d032f492009-09-29 00:33:46220}
221
[email protected]fb1277e82009-11-21 20:32:30222NaClProcessHost::~NaClProcessHost() {
[email protected]4cb43102011-12-02 20:24:49223 int exit_code;
[email protected]4967f792012-01-20 22:14:40224 process_->GetTerminationStatus(&exit_code);
[email protected]4cb43102011-12-02 20:24:49225 std::string message =
226 base::StringPrintf("NaCl process exited with status %i (0x%x)",
227 exit_code, exit_code);
228 if (exit_code == 0) {
229 LOG(INFO) << message;
230 } else {
231 LOG(ERROR) << message;
232 }
233
[email protected]c8e1ea32013-02-13 02:19:01234 if (internal_->socket_for_renderer != NACL_INVALID_HANDLE) {
235 if (NaClClose(internal_->socket_for_renderer) != 0) {
236 NOTREACHED() << "NaClClose() failed";
[email protected]909c2402011-05-09 11:39:04237 }
[email protected]c47ec402010-07-29 10:20:49238 }
[email protected]6294dd02013-01-09 17:27:23239
[email protected]c8e1ea32013-02-13 02:19:01240 if (internal_->socket_for_sel_ldr != NACL_INVALID_HANDLE) {
241 if (NaClClose(internal_->socket_for_sel_ldr) != 0) {
242 NOTREACHED() << "NaClClose() failed";
[email protected]909c2402011-05-09 11:39:04243 }
[email protected]c47ec402010-07-29 10:20:49244 }
245
[email protected]909c2402011-05-09 11:39:04246 if (reply_msg_) {
247 // The process failed to launch for some reason.
248 // Don't keep the renderer hanging.
249 reply_msg_->set_reply_error();
250 chrome_render_message_filter_->Send(reply_msg_);
251 }
[email protected]b39c6d92012-01-31 16:38:41252#if defined(OS_WIN)
[email protected]a575da52012-03-22 13:08:36253 if (process_launched_by_broker_) {
254 NaClBrokerService::GetInstance()->OnLoaderDied();
[email protected]5ca93be2012-03-21 20:04:06255 }
[email protected]b39c6d92012-01-31 16:38:41256#endif
[email protected]fb1277e82009-11-21 20:32:30257}
258
[email protected]773ebb92011-11-15 19:06:52259// This is called at browser startup.
260// static
261void NaClProcessHost::EarlyStartup() {
262#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
263 // Open the IRT file early to make sure that it isn't replaced out from
264 // under us by autoupdate.
265 NaClBrowser::GetInstance()->EnsureIrtAvailable();
266#endif
[email protected]9addd1c2012-09-15 14:28:24267 CommandLine* cmd = CommandLine::ForCurrentProcess();
268 UMA_HISTOGRAM_BOOLEAN(
269 "NaCl.nacl-gdb",
270 !cmd->GetSwitchValuePath(switches::kNaClGdb).empty());
271 UMA_HISTOGRAM_BOOLEAN(
272 "NaCl.nacl-gdb-script",
273 !cmd->GetSwitchValuePath(switches::kNaClGdbScript).empty());
274 UMA_HISTOGRAM_BOOLEAN(
275 "NaCl.enable-nacl-debug",
276 cmd->HasSwitch(switches::kEnableNaClDebug));
[email protected]66f409c2012-10-04 20:59:04277 NaClBrowser::GetInstance()->SetDebugPatterns(
278 cmd->GetSwitchValueASCII(switches::kNaClDebugMask));
[email protected]773ebb92011-11-15 19:06:52279}
280
[email protected]a575da52012-03-22 13:08:36281void NaClProcessHost::Launch(
[email protected]92d56412011-03-24 20:53:52282 ChromeRenderMessageFilter* chrome_render_message_filter,
[email protected]8f42b4d2012-03-24 14:12:33283 IPC::Message* reply_msg,
284 scoped_refptr<ExtensionInfoMap> extension_info_map) {
[email protected]a575da52012-03-22 13:08:36285 chrome_render_message_filter_ = chrome_render_message_filter;
286 reply_msg_ = reply_msg;
[email protected]8f42b4d2012-03-24 14:12:33287 extension_info_map_ = extension_info_map;
[email protected]a575da52012-03-22 13:08:36288
[email protected]773ebb92011-11-15 19:06:52289 // Start getting the IRT open asynchronously while we launch the NaCl process.
[email protected]09afc2e2012-04-10 17:29:03290 // We'll make sure this actually finished in StartWithLaunchedProcess, below.
[email protected]e97990f2012-05-15 22:06:06291 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
292 nacl_browser->EnsureAllResourcesAvailable();
293 if (!nacl_browser->IsOk()) {
[email protected]ec7540f2013-01-17 00:00:35294 LOG(ERROR) << "NaCl process launch failed: could not find all the "
295 "resources needed to launch the process";
[email protected]a575da52012-03-22 13:08:36296 delete this;
297 return;
[email protected]773ebb92011-11-15 19:06:52298 }
299
[email protected]c47ec402010-07-29 10:20:49300 // Rather than creating a socket pair in the renderer, and passing
301 // one side through the browser to sel_ldr, socket pairs are created
302 // in the browser and then passed to the renderer and sel_ldr.
303 //
304 // This is mainly for the benefit of Windows, where sockets cannot
305 // be passed in messages, but are copied via DuplicateHandle().
306 // This means the sandboxed renderer cannot send handles to the
307 // browser process.
308
[email protected]c8e1ea32013-02-13 02:19:01309 NaClHandle pair[2];
[email protected]6294dd02013-01-09 17:27:23310 // Create a connected socket
[email protected]c8e1ea32013-02-13 02:19:01311 if (NaClSocketPair(pair) == -1) {
[email protected]ec7540f2013-01-17 00:00:35312 LOG(ERROR) << "NaCl process launch failed: could not create a socket pair";
[email protected]6294dd02013-01-09 17:27:23313 delete this;
314 return;
[email protected]c47ec402010-07-29 10:20:49315 }
[email protected]6294dd02013-01-09 17:27:23316 internal_->socket_for_renderer = pair[0];
317 internal_->socket_for_sel_ldr = pair[1];
318 SetCloseOnExec(pair[0]);
319 SetCloseOnExec(pair[1]);
[email protected]d032f492009-09-29 00:33:46320
321 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30322 if (!LaunchSelLdr()) {
[email protected]a575da52012-03-22 13:08:36323 delete this;
[email protected]d032f492009-09-29 00:33:46324 }
[email protected]d032f492009-09-29 00:33:46325}
[email protected]646e15552012-04-06 22:01:04326
[email protected]5b974952012-04-05 18:18:23327#if defined(OS_WIN)
[email protected]646e15552012-04-06 22:01:04328void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
329 // Set process handle, if it was not set previously.
330 // This is needed when NaCl process is launched with nacl-gdb.
[email protected]82d17502012-05-23 19:12:40331 if (!CommandLine::ForCurrentProcess()->GetSwitchValuePath(
332 switches::kNaClGdb).empty()) {
[email protected]646e15552012-04-06 22:01:04333 base::ProcessHandle process;
[email protected]82d17502012-05-23 19:12:40334 DCHECK(process_->GetData().handle == base::kNullProcessHandle);
[email protected]646e15552012-04-06 22:01:04335 if (base::OpenProcessHandleWithAccess(
336 peer_pid,
337 base::kProcessAccessDuplicateHandle |
338 base::kProcessAccessQueryInformation |
339 base::kProcessAccessWaitForTermination,
340 &process)) {
341 process_->SetHandle(process);
[email protected]09afc2e2012-04-10 17:29:03342 if (!StartWithLaunchedProcess()) {
343 delete this;
344 return;
345 }
[email protected]646e15552012-04-06 22:01:04346 } else {
[email protected]ec7540f2013-01-17 00:00:35347 LOG(ERROR) << "Failed to get process handle";
[email protected]646e15552012-04-06 22:01:04348 }
349 }
[email protected]646e15552012-04-06 22:01:04350}
351#else
352void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
353}
354#endif
355
356#if defined(OS_WIN)
357void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
358 process_launched_by_broker_ = true;
359 process_->SetHandle(handle);
[email protected]09afc2e2012-04-10 17:29:03360 if (!StartWithLaunchedProcess())
361 delete this;
[email protected]646e15552012-04-06 22:01:04362}
363
[email protected]ea6588842012-05-03 05:39:38364void NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker(bool success) {
365 IPC::Message* reply = attach_debug_exception_handler_reply_msg_.release();
366 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply, success);
367 Send(reply);
[email protected]646e15552012-04-06 22:01:04368}
369#endif
370
371// Needed to handle sync messages in OnMessageRecieved.
372bool NaClProcessHost::Send(IPC::Message* msg) {
373 return process_->Send(msg);
374}
375
376#if defined(OS_WIN)
377scoped_ptr<CommandLine> NaClProcessHost::GetCommandForLaunchWithGdb(
[email protected]650b2d52013-02-10 03:41:45378 const base::FilePath& nacl_gdb,
[email protected]5b974952012-04-05 18:18:23379 CommandLine* line) {
[email protected]31a665e72012-03-11 12:37:46380 CommandLine* cmd_line = new CommandLine(nacl_gdb);
381 // We can't use PrependWrapper because our parameters contain spaces.
382 cmd_line->AppendArg("--eval-command");
[email protected]650b2d52013-02-10 03:41:45383 const base::FilePath::StringType& irt_path =
[email protected]31a665e72012-03-11 12:37:46384 NaClBrowser::GetInstance()->GetIrtFilePath().value();
385 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
[email protected]650b2d52013-02-10 03:41:45386 base::FilePath manifest_path = GetManifestPath();
[email protected]8f42b4d2012-03-24 14:12:33387 if (!manifest_path.empty()) {
388 cmd_line->AppendArg("--eval-command");
389 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
390 manifest_path.value());
391 }
[email protected]650b2d52013-02-10 03:41:45392 base::FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
[email protected]401b90792012-05-30 11:41:13393 switches::kNaClGdbScript);
394 if (!script.empty()) {
395 cmd_line->AppendArg("--command");
396 cmd_line->AppendArgNative(script.value());
397 }
[email protected]31a665e72012-03-11 12:37:46398 cmd_line->AppendArg("--args");
399 const CommandLine::StringVector& argv = line->argv();
400 for (size_t i = 0; i < argv.size(); i++) {
401 cmd_line->AppendArgNative(argv[i]);
402 }
403 return scoped_ptr<CommandLine>(cmd_line);
404}
[email protected]5b974952012-04-05 18:18:23405#elif defined(OS_LINUX)
[email protected]512d03f2012-06-26 01:06:06406class NaClProcessHost::NaClGdbWatchDelegate
[email protected]b3a25092013-05-28 22:08:16407 : public base::MessageLoopForIO::Watcher {
[email protected]5b974952012-04-05 18:18:23408 public:
409 // fd_write_ is used by nacl-gdb via /proc/browser_PID/fd/fd_write_
410 NaClGdbWatchDelegate(int fd_read, int fd_write,
411 const base::Closure& reply)
412 : fd_read_(fd_read),
413 fd_write_(fd_write),
414 reply_(reply) {}
415
[email protected]b94584a2013-02-07 03:02:08416 virtual ~NaClGdbWatchDelegate() {
[email protected]5b974952012-04-05 18:18:23417 if (HANDLE_EINTR(close(fd_read_)) != 0)
418 DLOG(ERROR) << "close(fd_read_) failed";
419 if (HANDLE_EINTR(close(fd_write_)) != 0)
420 DLOG(ERROR) << "close(fd_write_) failed";
421 }
422
423 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
424 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
425
426 private:
427 int fd_read_;
428 int fd_write_;
429 base::Closure reply_;
430};
431
[email protected]512d03f2012-06-26 01:06:06432void NaClProcessHost::NaClGdbWatchDelegate::OnFileCanReadWithoutBlocking(
433 int fd) {
[email protected]5b974952012-04-05 18:18:23434 char buf;
435 if (HANDLE_EINTR(read(fd_read_, &buf, 1)) != 1 || buf != '\0')
436 LOG(ERROR) << "Failed to sync with nacl-gdb";
437 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, reply_);
438}
[email protected]5b974952012-04-05 18:18:23439
440bool NaClProcessHost::LaunchNaClGdb(base::ProcessId pid) {
441 CommandLine::StringType nacl_gdb =
442 CommandLine::ForCurrentProcess()->GetSwitchValueNative(
443 switches::kNaClGdb);
444 CommandLine::StringVector argv;
445 // We don't support spaces inside arguments in --nacl-gdb switch.
446 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
447 CommandLine cmd_line(argv);
448 cmd_line.AppendArg("--eval-command");
[email protected]650b2d52013-02-10 03:41:45449 const base::FilePath::StringType& irt_path =
[email protected]5b974952012-04-05 18:18:23450 NaClBrowser::GetInstance()->GetIrtFilePath().value();
451 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
[email protected]650b2d52013-02-10 03:41:45452 base::FilePath manifest_path = GetManifestPath();
[email protected]5b974952012-04-05 18:18:23453 if (!manifest_path.empty()) {
454 cmd_line.AppendArg("--eval-command");
455 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
456 manifest_path.value());
457 }
458 cmd_line.AppendArg("--eval-command");
459 cmd_line.AppendArg("attach " + base::IntToString(pid));
460 int fds[2];
461 if (pipe(fds) != 0)
462 return false;
463 // Tell the debugger to send a byte to the writable end of the pipe.
464 // We use a file descriptor in our process because the debugger will be
465 // typically launched in a separate terminal, and a lot of terminals close all
466 // file descriptors before launching external programs.
467 cmd_line.AppendArg("--eval-command");
468 cmd_line.AppendArg("dump binary value /proc/" +
469 base::IntToString(base::GetCurrentProcId()) +
470 "/fd/" + base::IntToString(fds[1]) + " (char)0");
[email protected]650b2d52013-02-10 03:41:45471 base::FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
[email protected]401b90792012-05-30 11:41:13472 switches::kNaClGdbScript);
473 if (!script.empty()) {
474 cmd_line.AppendArg("--command");
475 cmd_line.AppendArgNative(script.value());
476 }
[email protected]5b974952012-04-05 18:18:23477 // wait on fds[0]
478 // If the debugger crashes before attaching to the NaCl process, the user can
479 // release resources by terminating the NaCl loader in Chrome Task Manager.
480 nacl_gdb_watcher_delegate_.reset(
481 new NaClGdbWatchDelegate(
482 fds[0], fds[1],
483 base::Bind(&NaClProcessHost::OnNaClGdbAttached,
484 weak_factory_.GetWeakPtr())));
[email protected]b3a25092013-05-28 22:08:16485 base::MessageLoopForIO::current()->WatchFileDescriptor(
[email protected]5b974952012-04-05 18:18:23486 fds[0],
487 true,
[email protected]b3a25092013-05-28 22:08:16488 base::MessageLoopForIO::WATCH_READ,
[email protected]5b974952012-04-05 18:18:23489 &nacl_gdb_watcher_,
490 nacl_gdb_watcher_delegate_.get());
491 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
492}
493
494void NaClProcessHost::OnNaClGdbAttached() {
495 wait_for_nacl_gdb_ = false;
496 nacl_gdb_watcher_.StopWatchingFileDescriptor();
497 nacl_gdb_watcher_delegate_.reset();
498 OnProcessLaunched();
499}
500#endif
501
[email protected]650b2d52013-02-10 03:41:45502base::FilePath NaClProcessHost::GetManifestPath() {
[email protected]1c321ee2012-05-21 03:02:34503 const extensions::Extension* extension = extension_info_map_->extensions()
[email protected]87f35592012-04-08 00:49:16504 .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url_));
[email protected]885c0e92012-11-13 20:27:42505 if (extension != NULL &&
506 manifest_url_.SchemeIs(extensions::kExtensionScheme)) {
[email protected]87f35592012-04-08 00:49:16507 std::string path = manifest_url_.path();
[email protected]5b974952012-04-05 18:18:23508 TrimString(path, "/", &path); // Remove first slash
509 return extension->path().AppendASCII(path);
510 }
[email protected]650b2d52013-02-10 03:41:45511 return base::FilePath();
[email protected]5b974952012-04-05 18:18:23512}
[email protected]31a665e72012-03-11 12:37:46513
[email protected]fb1277e82009-11-21 20:32:30514bool NaClProcessHost::LaunchSelLdr() {
[email protected]4967f792012-01-20 22:14:40515 std::string channel_id = process_->GetHost()->CreateChannel();
[email protected]ec7540f2013-01-17 00:00:35516 if (channel_id.empty()) {
517 LOG(ERROR) << "NaCl process launch failed: could not create channel";
[email protected]d032f492009-09-29 00:33:46518 return false;
[email protected]ec7540f2013-01-17 00:00:35519 }
[email protected]d032f492009-09-29 00:33:46520
[email protected]e3fc75a2011-05-05 08:20:42521 CommandLine::StringType nacl_loader_prefix;
522#if defined(OS_POSIX)
523 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
524 switches::kNaClLoaderCmdPrefix);
525#endif // defined(OS_POSIX)
526
[email protected]d032f492009-09-29 00:33:46527 // Build command line for nacl.
[email protected]8c40f322011-08-24 03:33:36528
529#if defined(OS_MACOSX)
530 // The Native Client process needs to be able to allocate a 1GB contiguous
531 // region to use as the client environment's virtual address space. ASLR
532 // (PIE) interferes with this by making it possible that no gap large enough
533 // to accomodate this request will exist in the child process' address
534 // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
535 // http://code.google.com/p/nativeclient/issues/detail?id=2043.
[email protected]4cb43102011-12-02 20:24:49536 int flags = ChildProcessHost::CHILD_NO_PIE;
[email protected]8c40f322011-08-24 03:33:36537#elif defined(OS_LINUX)
[email protected]4cb43102011-12-02 20:24:49538 int flags = nacl_loader_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
539 ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36540#else
[email protected]4cb43102011-12-02 20:24:49541 int flags = ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36542#endif
543
[email protected]650b2d52013-02-10 03:41:45544 base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
[email protected]fb1277e82009-11-21 20:32:30545 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46546 return false;
547
[email protected]31a665e72012-03-11 12:37:46548#if defined(OS_WIN)
549 // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
550 if (RunningOnWOW64()) {
[email protected]650b2d52013-02-10 03:41:45551 base::FilePath module_path;
[email protected]ec7540f2013-01-17 00:00:35552 if (!PathService::Get(base::FILE_MODULE, &module_path)) {
553 LOG(ERROR) << "NaCl process launch failed: could not resolve module";
[email protected]31a665e72012-03-11 12:37:46554 return false;
[email protected]ec7540f2013-01-17 00:00:35555 }
[email protected]31a665e72012-03-11 12:37:46556 exe_path = module_path.DirName().Append(chrome::kNaClAppName);
557 }
558#endif
559
[email protected]33a05af2012-03-02 18:15:51560 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
561 nacl::CopyNaClCommandLineArguments(cmd_line.get());
[email protected]599e6642010-01-27 18:52:13562
[email protected]05076ba22010-07-30 05:59:57563 cmd_line->AppendSwitchASCII(switches::kProcessType,
564 switches::kNaClLoaderProcess);
[email protected]4734d0b2011-12-03 07:10:44565 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
[email protected]93156cec2011-09-12 21:14:44566 if (logging::DialogsAreSuppressed())
567 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
[email protected]d032f492009-09-29 00:33:46568
[email protected]e3fc75a2011-05-05 08:20:42569 if (!nacl_loader_prefix.empty())
570 cmd_line->PrependWrapper(nacl_loader_prefix);
571
[email protected]650b2d52013-02-10 03:41:45572 base::FilePath nacl_gdb =
573 CommandLine::ForCurrentProcess()->GetSwitchValuePath(switches::kNaClGdb);
[email protected]31a665e72012-03-11 12:37:46574 if (!nacl_gdb.empty()) {
[email protected]5b974952012-04-05 18:18:23575#if defined(OS_WIN)
[email protected]31a665e72012-03-11 12:37:46576 cmd_line->AppendSwitch(switches::kNoSandbox);
577 scoped_ptr<CommandLine> gdb_cmd_line(
[email protected]646e15552012-04-06 22:01:04578 GetCommandForLaunchWithGdb(nacl_gdb, cmd_line.get()));
[email protected]31a665e72012-03-11 12:37:46579 // We can't use process_->Launch() because OnProcessLaunched will be called
580 // with process_->GetData().handle filled by handle of gdb process. This
581 // handle will be used to duplicate handles for NaCl process and as
582 // a result NaCl process will not be able to use them.
583 //
584 // So we don't fill process_->GetData().handle and wait for
585 // OnChannelConnected to get handle of NaCl process from its pid. Then we
586 // call OnProcessLaunched.
587 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL);
[email protected]5b974952012-04-05 18:18:23588#elif defined(OS_LINUX)
589 wait_for_nacl_gdb_ = true;
590#endif
[email protected]31a665e72012-03-11 12:37:46591 }
592
[email protected]103607e2010-02-01 18:57:09593 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46594#if defined(OS_WIN)
[email protected]773ebb92011-11-15 19:06:52595 if (RunningOnWOW64()) {
[email protected]ec7540f2013-01-17 00:00:35596 if (!NaClBrokerService::GetInstance()->LaunchLoader(
597 weak_factory_.GetWeakPtr(), channel_id)) {
598 LOG(ERROR) << "NaCl process launch failed: broker service did not launch "
599 "process";
600 return false;
601 }
[email protected]4bdde602010-06-16 03:17:35602 } else {
[email protected]34f48682013-03-20 00:30:18603 process_->Launch(new NaClSandboxedProcessLauncherDelegate,
604 cmd_line.release());
[email protected]4bdde602010-06-16 03:17:35605 }
[email protected]103607e2010-02-01 18:57:09606#elif defined(OS_POSIX)
[email protected]4967f792012-01-20 22:14:40607 process_->Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]a82af392012-02-24 04:40:20608 base::EnvironmentVector(),
[email protected]33a05af2012-03-02 18:15:51609 cmd_line.release());
[email protected]103607e2010-02-01 18:57:09610#endif
[email protected]d032f492009-09-29 00:33:46611
[email protected]fb1277e82009-11-21 20:32:30612 return true;
[email protected]d032f492009-09-29 00:33:46613}
614
[email protected]646e15552012-04-06 22:01:04615bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
616 bool handled = true;
617 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
618 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
619 OnQueryKnownToValidate)
620 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
621 OnSetKnownToValidate)
[email protected]041834522013-05-29 00:19:27622 IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_ResolveFileToken,
623 OnResolveFileToken)
[email protected]ea6588842012-05-03 05:39:38624#if defined(OS_WIN)
625 IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_AttachDebugExceptionHandler,
626 OnAttachDebugExceptionHandler)
627#endif
[email protected]17b5a8172012-06-22 21:09:09628 IPC_MESSAGE_HANDLER(NaClProcessHostMsg_PpapiChannelCreated,
629 OnPpapiChannelCreated)
[email protected]646e15552012-04-06 22:01:04630 IPC_MESSAGE_UNHANDLED(handled = false)
631 IPC_END_MESSAGE_MAP()
632 return handled;
[email protected]103607e2010-02-01 18:57:09633}
634
[email protected]773ebb92011-11-15 19:06:52635void NaClProcessHost::OnProcessLaunched() {
[email protected]09afc2e2012-04-10 17:29:03636 if (!StartWithLaunchedProcess())
637 delete this;
[email protected]773ebb92011-11-15 19:06:52638}
639
[email protected]e97990f2012-05-15 22:06:06640// Called when the NaClBrowser singleton has been fully initialized.
641void NaClProcessHost::OnResourcesReady() {
[email protected]773ebb92011-11-15 19:06:52642 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]ec7540f2013-01-17 00:00:35643 if (!nacl_browser->IsReady()) {
644 LOG(ERROR) << "NaCl process launch failed: could not acquire shared "
645 "resources needed by NaCl";
646 delete this;
647 } else if (!SendStart()) {
[email protected]338466a82011-05-03 04:27:43648 delete this;
649 }
650}
651
[email protected]17b5a8172012-06-22 21:09:09652bool NaClProcessHost::ReplyToRenderer(
653 const IPC::ChannelHandle& channel_handle) {
[email protected]6294dd02013-01-09 17:27:23654 nacl::FileDescriptor handle_for_renderer;
[email protected]c47ec402010-07-29 10:20:49655#if defined(OS_WIN)
[email protected]6294dd02013-01-09 17:27:23656 // Copy the handle into the renderer process.
657 HANDLE handle_in_renderer;
658 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
659 reinterpret_cast<HANDLE>(
660 internal_->socket_for_renderer),
661 chrome_render_message_filter_->peer_handle(),
662 &handle_in_renderer,
663 0, // Unused given DUPLICATE_SAME_ACCESS.
664 FALSE,
665 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
[email protected]ec7540f2013-01-17 00:00:35666 LOG(ERROR) << "DuplicateHandle() failed";
[email protected]6294dd02013-01-09 17:27:23667 return false;
[email protected]c47ec402010-07-29 10:20:49668 }
[email protected]6294dd02013-01-09 17:27:23669 handle_for_renderer = reinterpret_cast<nacl::FileDescriptor>(
670 handle_in_renderer);
671#else
672 // No need to dup the imc_handle - we don't pass it anywhere else so
673 // it cannot be closed.
674 nacl::FileDescriptor imc_handle;
675 imc_handle.fd = internal_->socket_for_renderer;
676 imc_handle.auto_close = true;
677 handle_for_renderer = imc_handle;
678#endif
[email protected]c47ec402010-07-29 10:20:49679
680#if defined(OS_WIN)
[email protected]e4f6eb0232012-04-17 00:47:50681 // If we are on 64-bit Windows, the NaCl process's sandbox is
682 // managed by a different process from the renderer's sandbox. We
683 // need to inform the renderer's sandbox about the NaCl process so
684 // that the renderer can send handles to the NaCl process using
685 // BrokerDuplicateHandle().
686 if (RunningOnWOW64()) {
[email protected]171fa98d2012-04-23 21:34:01687 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
[email protected]ec7540f2013-01-17 00:00:35688 LOG(ERROR) << "Failed to add NaCl process PID";
[email protected]e4f6eb0232012-04-17 00:47:50689 return false;
690 }
691 }
[email protected]fb1277e82009-11-21 20:32:30692#endif
693
[email protected]108fd342013-01-04 20:46:54694 const ChildProcessData& data = process_->GetData();
[email protected]2ccf45c2011-08-19 23:35:50695 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]6294dd02013-01-09 17:27:23696 reply_msg_, handle_for_renderer,
[email protected]108fd342013-01-04 20:46:54697 channel_handle, base::GetProcId(data.handle), data.id);
[email protected]92d56412011-03-24 20:53:52698 chrome_render_message_filter_->Send(reply_msg_);
699 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30700 reply_msg_ = NULL;
[email protected]c8e1ea32013-02-13 02:19:01701 internal_->socket_for_renderer = NACL_INVALID_HANDLE;
[email protected]00d99542012-04-17 22:48:02702 return true;
703}
[email protected]fb1277e82009-11-21 20:32:30704
[email protected]d571c032012-09-14 12:39:18705// TCP port we chose for NaCl debug stub. It can be any other number.
706static const int kDebugStubPort = 4014;
707
708#if defined(OS_POSIX)
709SocketDescriptor NaClProcessHost::GetDebugStubSocketHandle() {
[email protected]13cad0b2012-12-07 17:57:34710 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
711 SocketDescriptor s;
712 // We allocate currently unused TCP port for debug stub tests. The port
713 // number is passed to the test via debug stub port listener.
714 if (nacl_browser->HasGdbDebugStubPortListener()) {
715 int port;
716 s = net::TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port);
717 if (s != net::TCPListenSocket::kInvalidSocket) {
718 nacl_browser->FireGdbDebugStubPortOpened(port);
719 }
720 } else {
721 s = net::TCPListenSocket::CreateAndBind("127.0.0.1", kDebugStubPort);
722 }
723 if (s == net::TCPListenSocket::kInvalidSocket) {
724 LOG(ERROR) << "failed to open socket for debug stub";
725 return net::TCPListenSocket::kInvalidSocket;
726 }
[email protected]d571c032012-09-14 12:39:18727 if (listen(s, 1)) {
728 LOG(ERROR) << "listen() failed on debug stub socket";
[email protected]13cad0b2012-12-07 17:57:34729 if (HANDLE_EINTR(close(s)) < 0)
730 PLOG(ERROR) << "failed to close debug stub socket";
[email protected]d571c032012-09-14 12:39:18731 return net::TCPListenSocket::kInvalidSocket;
732 }
733 return s;
734}
735#endif
736
[email protected]00d99542012-04-17 22:48:02737bool NaClProcessHost::StartNaClExecution() {
738 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
739
740 nacl::NaClStartParams params;
[email protected]8c670832012-05-26 04:30:12741 params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
742 params.validation_cache_key = nacl_browser->GetValidationCacheKey();
[email protected]00d99542012-04-17 22:48:02743 params.version = chrome::VersionInfo().CreateVersionString();
744 params.enable_exception_handling = enable_exception_handling_;
[email protected]66f409c2012-10-04 20:59:04745 params.enable_debug_stub = enable_debug_stub_ &&
746 NaClBrowser::GetInstance()->URLMatchesDebugPatterns(manifest_url_);
[email protected]7522077b2013-01-17 23:39:40747 // Enable PPAPI proxy channel creation only for renderer processes.
748 params.enable_ipc_proxy = enable_ppapi_proxy();
[email protected]2e1e6f02013-01-11 18:22:56749 params.uses_irt = uses_irt_;
[email protected]be524622013-04-23 00:12:19750 params.enable_dyncode_syscalls = enable_dyncode_syscalls_;
[email protected]00d99542012-04-17 22:48:02751
752 const ChildProcessData& data = process_->GetData();
[email protected]6294dd02013-01-09 17:27:23753 if (!ShareHandleToSelLdr(data.handle,
754 internal_->socket_for_sel_ldr, true,
755 &params.handles)) {
756 return false;
[email protected]773ebb92011-11-15 19:06:52757 }
758
[email protected]2e1e6f02013-01-11 18:22:56759 if (params.uses_irt) {
760 base::PlatformFile irt_file = nacl_browser->IrtFile();
761 CHECK_NE(irt_file, base::kInvalidPlatformFileValue);
[email protected]2e1e6f02013-01-11 18:22:56762 // Send over the IRT file handle. We don't close our own copy!
763 if (!ShareHandleToSelLdr(data.handle, irt_file, false, &params.handles))
764 return false;
765 }
[email protected]c47ec402010-07-29 10:20:49766
[email protected]ab88d1542011-11-18 22:52:00767#if defined(OS_MACOSX)
768 // For dynamic loading support, NaCl requires a file descriptor that
769 // was created in /tmp, since those created with shm_open() are not
770 // mappable with PROT_EXEC. Rather than requiring an extra IPC
771 // round trip out of the sandbox, we create an FD here.
[email protected]cbbe7842011-11-17 22:01:25772 base::SharedMemory memory_buffer;
[email protected]b05df6b2011-12-01 23:19:31773 base::SharedMemoryCreateOptions options;
774 options.size = 1;
775 options.executable = true;
776 if (!memory_buffer.Create(options)) {
[email protected]09afc2e2012-04-10 17:29:03777 DLOG(ERROR) << "Failed to allocate memory buffer";
778 return false;
[email protected]2c68bf032010-11-11 23:16:30779 }
[email protected]cbbe7842011-11-17 22:01:25780 nacl::FileDescriptor memory_fd;
781 memory_fd.fd = dup(memory_buffer.handle().fd);
782 if (memory_fd.fd < 0) {
[email protected]09afc2e2012-04-10 17:29:03783 DLOG(ERROR) << "Failed to dup() a file descriptor";
784 return false;
[email protected]cbbe7842011-11-17 22:01:25785 }
786 memory_fd.auto_close = true;
[email protected]00d99542012-04-17 22:48:02787 params.handles.push_back(memory_fd);
[email protected]2c68bf032010-11-11 23:16:30788#endif
789
[email protected]d571c032012-09-14 12:39:18790#if defined(OS_POSIX)
[email protected]ed637bb2012-10-15 17:36:05791 if (params.enable_debug_stub) {
[email protected]d571c032012-09-14 12:39:18792 SocketDescriptor server_bound_socket = GetDebugStubSocketHandle();
793 if (server_bound_socket != net::TCPListenSocket::kInvalidSocket) {
794 params.debug_stub_server_bound_socket =
795 nacl::FileDescriptor(server_bound_socket, true);
796 }
797 }
798#endif
799
[email protected]ea6588842012-05-03 05:39:38800 process_->Send(new NaClProcessMsg_Start(params));
[email protected]b39c6d92012-01-31 16:38:41801
[email protected]c8e1ea32013-02-13 02:19:01802 internal_->socket_for_sel_ldr = NACL_INVALID_HANDLE;
[email protected]09afc2e2012-04-10 17:29:03803 return true;
804}
805
[email protected]00d99542012-04-17 22:48:02806bool NaClProcessHost::SendStart() {
[email protected]7522077b2013-01-17 23:39:40807 if (!enable_ppapi_proxy()) {
[email protected]17b5a8172012-06-22 21:09:09808 if (!ReplyToRenderer(IPC::ChannelHandle()))
809 return false;
810 }
811 return StartNaClExecution();
812}
813
[email protected]8510d282012-08-30 19:47:38814// This method is called when NaClProcessHostMsg_PpapiChannelCreated is
815// received or PpapiHostMsg_ChannelCreated is forwarded by our plugin
816// listener.
[email protected]17b5a8172012-06-22 21:09:09817void NaClProcessHost::OnPpapiChannelCreated(
818 const IPC::ChannelHandle& channel_handle) {
[email protected]7522077b2013-01-17 23:39:40819 // Only renderer processes should create a channel.
820 DCHECK(enable_ppapi_proxy());
[email protected]8510d282012-08-30 19:47:38821 // If the proxy channel is null, this must be the initial NaCl-Browser IPC
822 // channel.
823 if (!ipc_proxy_channel_.get()) {
[email protected]f3b357692013-03-22 05:16:13824 DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
[email protected]9e141212013-01-21 15:21:56825
[email protected]8510d282012-08-30 19:47:38826 ipc_proxy_channel_.reset(
827 new IPC::ChannelProxy(channel_handle,
828 IPC::Channel::MODE_CLIENT,
829 &ipc_plugin_listener_,
830 base::MessageLoopProxy::current()));
[email protected]0c7193742012-11-07 19:05:03831 // Create the browser ppapi host and enable PPAPI message dispatching to the
832 // browser process.
[email protected]adf7cd52012-12-04 19:37:46833 ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
[email protected]9e141212013-01-21 15:21:56834 ipc_proxy_channel_.get(), // sender
[email protected]0c7193742012-11-07 19:05:03835 permissions_,
836 process_->GetData().handle,
[email protected]b4b53d182012-09-12 02:56:55837 ipc_proxy_channel_.get(),
[email protected]e02ff722012-11-06 03:53:06838 chrome_render_message_filter_->GetHostResolver(),
839 chrome_render_message_filter_->render_process_id(),
[email protected]7bb5d2c2013-04-29 22:33:49840 render_view_id_,
841 profile_directory_));
[email protected]adf7cd52012-12-04 19:37:46842
[email protected]ac07ec52013-04-22 17:32:45843 ppapi::PpapiNaClChannelArgs args;
844 args.off_the_record = chrome_render_message_filter_->off_the_record();
845 args.permissions = permissions_;
846 CommandLine* cmdline = CommandLine::ForCurrentProcess();
847 DCHECK(cmdline);
848 std::string flag_whitelist[] = {switches::kV, switches::kVModule};
849 for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
850 std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
851 if (!value.empty()) {
852 args.switch_names.push_back(flag_whitelist[i]);
853 args.switch_values.push_back(value);
854 }
855 }
856
[email protected]4b30e7d2013-04-24 23:52:14857 ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
858 scoped_ptr<ppapi::host::HostFactory>(
859 new chrome::ChromeBrowserPepperHostFactory(ppapi_host_.get())));
860
[email protected]8510d282012-08-30 19:47:38861 // Send a message to create the NaCl-Renderer channel. The handle is just
862 // a place holder.
863 ipc_proxy_channel_->Send(
864 new PpapiMsg_CreateNaClChannel(
865 chrome_render_message_filter_->render_process_id(),
[email protected]ac07ec52013-04-22 17:32:45866 args,
[email protected]8510d282012-08-30 19:47:38867 SerializedHandle(SerializedHandle::CHANNEL_HANDLE,
868 IPC::InvalidPlatformFileForTransit())));
869 } else if (reply_msg_) {
870 // Otherwise, this must be a renderer channel.
871 ReplyToRenderer(channel_handle);
872 } else {
873 // Attempt to open more than 1 renderer channel is not supported.
874 // Shut down the NaCl process.
875 process_->GetHost()->ForceShutdown();
876 }
877}
878
879bool NaClProcessHost::OnUntrustedMessageForwarded(const IPC::Message& msg) {
880 // Handle messages that have been forwarded from our PluginListener.
881 // These messages come from untrusted code so should be handled with care.
882 bool handled = true;
883 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
884 IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated,
885 OnPpapiChannelCreated)
886 IPC_MESSAGE_UNHANDLED(handled = false)
887 IPC_END_MESSAGE_MAP()
888 return handled;
[email protected]00d99542012-04-17 22:48:02889}
890
[email protected]09afc2e2012-04-10 17:29:03891bool NaClProcessHost::StartWithLaunchedProcess() {
892#if defined(OS_LINUX)
893 if (wait_for_nacl_gdb_) {
894 if (LaunchNaClGdb(base::GetProcId(process_->GetData().handle))) {
895 // We will be called with wait_for_nacl_gdb_ = false once debugger is
896 // attached to the program.
897 return true;
898 }
899 DLOG(ERROR) << "Failed to launch debugger";
900 // Continue execution without debugger.
901 }
902#endif
903
904 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]09afc2e2012-04-10 17:29:03905
[email protected]e97990f2012-05-15 22:06:06906 if (nacl_browser->IsReady()) {
907 return SendStart();
908 } else if (nacl_browser->IsOk()) {
909 nacl_browser->WaitForResources(
910 base::Bind(&NaClProcessHost::OnResourcesReady,
911 weak_factory_.GetWeakPtr()));
912 return true;
913 } else {
[email protected]ec7540f2013-01-17 00:00:35914 LOG(ERROR) << "NaCl process failed to launch: previously failed to acquire "
915 "shared resources";
[email protected]e97990f2012-05-15 22:06:06916 return false;
917 }
[email protected]d032f492009-09-29 00:33:46918}
919
[email protected]4a0141b2012-03-27 01:15:30920void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
921 bool* result) {
[email protected]7cfaf982012-05-09 18:37:47922 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]57473ebc2012-05-30 07:44:52923 *result = nacl_browser->QueryKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30924}
925
926void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
[email protected]57473ebc2012-05-30 07:44:52927 NaClBrowser::GetInstance()->SetKnownToValidate(signature, off_the_record_);
[email protected]4a0141b2012-03-27 01:15:30928}
[email protected]ea6588842012-05-03 05:39:38929
[email protected]041834522013-05-29 00:19:27930void NaClProcessHost::FileResolved(
931 base::PlatformFile* file,
932 const base::FilePath& file_path,
933 IPC::Message* reply_msg) {
934 if (*file != base::kInvalidPlatformFileValue) {
935 IPC::PlatformFileForTransit handle = IPC::GetFileHandleForProcess(
936 *file,
937 process_->GetData().handle,
938 true /* close_source */);
939 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
940 reply_msg,
941 handle,
942 file_path);
943 } else {
944 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
945 reply_msg,
946 IPC::InvalidPlatformFileForTransit(),
947 base::FilePath(FILE_PATH_LITERAL("")));
948 }
949 Send(reply_msg);
950}
951
952void NaClProcessHost::OnResolveFileToken(uint64 file_token_lo,
953 uint64 file_token_hi,
954 IPC::Message* reply_msg) {
955 // Was the file registered?
956 //
957 // Note that the file path cache is of bounded size, and old entries can get
958 // evicted. If a large number of NaCl modules are being launched at once,
959 // resolving the file_token may fail because the path cache was thrashed
960 // while the file_token was in flight. In this case the query fails, and we
961 // need to fall back to the slower path.
962 //
963 // However: each NaCl process will consume 2-3 entries as it starts up, this
964 // means that eviction will not happen unless you start up 33+ NaCl processes
965 // at the same time, and this still requires worst-case timing. As a
966 // practical matter, no entries should be evicted prematurely.
967 // The cache itself should take ~ (150 characters * 2 bytes/char + ~60 bytes
968 // data structure overhead) * 100 = 35k when full, so making it bigger should
969 // not be a problem, if needed.
970 //
971 // Each NaCl process will consume 2-3 entries because the manifest and main
972 // nexe are currently not resolved. Shared libraries will be resolved. They
973 // will be loaded sequentially, so they will only consume a single entry
974 // while the load is in flight.
975 //
976 // TODO(ncbray): track behavior with UMA. If entries are getting evicted or
977 // bogus keys are getting queried, this would be good to know.
978 base::FilePath file_path;
979 if (!NaClBrowser::GetInstance()->GetFilePath(file_token_lo, file_token_hi,
980 &file_path)) {
981 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
982 reply_msg,
983 IPC::InvalidPlatformFileForTransit(),
984 base::FilePath(FILE_PATH_LITERAL("")));
985 Send(reply_msg);
986 return;
987 }
988
989 // Scratch space to share between the callbacks.
990 base::PlatformFile* data = new base::PlatformFile();
991
992 // Open the file.
993 if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
994 FROM_HERE,
995 base::Bind(nacl::OpenNaClExecutableImpl,
996 file_path, data),
997 base::Bind(&NaClProcessHost::FileResolved,
998 weak_factory_.GetWeakPtr(),
999 base::Owned(data),
1000 file_path,
1001 reply_msg))) {
1002 NaClProcessMsg_ResolveFileToken::WriteReplyParams(
1003 reply_msg,
1004 IPC::InvalidPlatformFileForTransit(),
1005 base::FilePath(FILE_PATH_LITERAL("")));
1006 Send(reply_msg);
1007 }
1008}
1009
[email protected]ea6588842012-05-03 05:39:381010#if defined(OS_WIN)
1011void NaClProcessHost::OnAttachDebugExceptionHandler(const std::string& info,
1012 IPC::Message* reply_msg) {
1013 if (!AttachDebugExceptionHandler(info, reply_msg)) {
1014 // Send failure message.
1015 NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply_msg,
1016 false);
1017 Send(reply_msg);
1018 }
1019}
1020
1021bool NaClProcessHost::AttachDebugExceptionHandler(const std::string& info,
1022 IPC::Message* reply_msg) {
[email protected]2c227ff2012-08-11 00:51:321023 if (!enable_exception_handling_ && !enable_debug_stub_) {
[email protected]ea6588842012-05-03 05:39:381024 DLOG(ERROR) <<
[email protected]2c227ff2012-08-11 00:51:321025 "Debug exception handler requested by NaCl process when not enabled";
[email protected]ea6588842012-05-03 05:39:381026 return false;
1027 }
1028 if (debug_exception_handler_requested_) {
1029 // The NaCl process should not request this multiple times.
1030 DLOG(ERROR) << "Multiple AttachDebugExceptionHandler requests received";
1031 return false;
1032 }
1033 debug_exception_handler_requested_ = true;
1034
1035 base::ProcessId nacl_pid = base::GetProcId(process_->GetData().handle);
1036 base::win::ScopedHandle process_handle;
1037 // We cannot use process_->GetData().handle because it does not have
1038 // the necessary access rights. We open the new handle here rather
1039 // than in the NaCl broker process in case the NaCl loader process
1040 // dies before the NaCl broker process receives the message we send.
1041 // The debug exception handler uses DebugActiveProcess() to attach,
1042 // but this takes a PID. We need to prevent the NaCl loader's PID
1043 // from being reused before DebugActiveProcess() is called, and
1044 // holding a process handle open achieves this.
1045 if (!base::OpenProcessHandleWithAccess(
1046 nacl_pid,
1047 base::kProcessAccessQueryInformation |
1048 base::kProcessAccessSuspendResume |
1049 base::kProcessAccessTerminate |
1050 base::kProcessAccessVMOperation |
1051 base::kProcessAccessVMRead |
1052 base::kProcessAccessVMWrite |
[email protected]29172322013-01-10 17:35:161053 base::kProcessAccessDuplicateHandle |
[email protected]ea6588842012-05-03 05:39:381054 base::kProcessAccessWaitForTermination,
1055 process_handle.Receive())) {
1056 LOG(ERROR) << "Failed to get process handle";
1057 return false;
1058 }
1059
1060 attach_debug_exception_handler_reply_msg_.reset(reply_msg);
1061 // If the NaCl loader is 64-bit, the process running its debug
1062 // exception handler must be 64-bit too, so we use the 64-bit NaCl
1063 // broker process for this. Otherwise, on a 32-bit system, we use
1064 // the 32-bit browser process to run the debug exception handler.
1065 if (RunningOnWOW64()) {
1066 return NaClBrokerService::GetInstance()->LaunchDebugExceptionHandler(
[email protected]fd37bf62012-05-04 16:46:481067 weak_factory_.GetWeakPtr(), nacl_pid, process_handle, info);
[email protected]ea6588842012-05-03 05:39:381068 } else {
1069 NaClStartDebugExceptionHandlerThread(
[email protected]fd37bf62012-05-04 16:46:481070 process_handle.Take(), info,
[email protected]ea6588842012-05-03 05:39:381071 base::MessageLoopProxy::current(),
1072 base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
1073 weak_factory_.GetWeakPtr()));
1074 return true;
1075 }
1076}
1077#endif