blob: e58d747896971da53368ddcb68526f157cc0cc6d [file] [log] [blame]
[email protected]b39c6d92012-01-31 16:38:411// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]d032f492009-09-29 00:33:462// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]e15a4fa2010-02-11 23:09:295#include "chrome/browser/nacl_host/nacl_process_host.h"
[email protected]d032f492009-09-29 00:33:466
[email protected]a82af392012-02-24 04:40:207#include <string>
8#include <vector>
[email protected]d032f492009-09-29 00:33:469
[email protected]30c1eea2011-10-17 18:40:3010#include "base/bind.h"
[email protected]103607e2010-02-01 18:57:0911#include "base/command_line.h"
[email protected]4a0141b2012-03-27 01:15:3012#include "base/memory/mru_cache.h"
[email protected]4734d0b2011-12-03 07:10:4413#include "base/memory/singleton.h"
[email protected]5b974952012-04-05 18:18:2314#include "base/message_loop.h"
[email protected]0ae52b42012-03-27 02:53:5915#include "base/metrics/histogram.h"
[email protected]338466a82011-05-03 04:27:4316#include "base/path_service.h"
[email protected]5b974952012-04-05 18:18:2317#include "base/string_number_conversions.h"
18#include "base/string_split.h"
[email protected]8f42b4d2012-03-24 14:12:3319#include "base/string_util.h"
[email protected]1657e6d2012-03-30 20:28:0020#include "base/rand_util.h"
[email protected]a0a69bf2011-09-23 21:40:2821#include "base/stringprintf.h"
[email protected]be1ce6a72010-08-03 14:35:2222#include "base/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"
26#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
[email protected]31a665e72012-03-11 12:37:4627#include "chrome/common/chrome_constants.h"
[email protected]338466a82011-05-03 04:27:4328#include "chrome/common/chrome_paths.h"
[email protected]d032f492009-09-29 00:33:4629#include "chrome/common/chrome_switches.h"
[email protected]1657e6d2012-03-30 20:28:0030#include "chrome/common/chrome_version_info.h"
[email protected]d032f492009-09-29 00:33:4631#include "chrome/common/logging_chrome.h"
[email protected]103607e2010-02-01 18:57:0932#include "chrome/common/nacl_cmd_line.h"
[email protected]d032f492009-09-29 00:33:4633#include "chrome/common/nacl_messages.h"
[email protected]fb1277e82009-11-21 20:32:3034#include "chrome/common/render_messages.h"
[email protected]8f42b4d2012-03-24 14:12:3335#include "chrome/common/url_constants.h"
[email protected]4967f792012-01-20 22:14:4036#include "content/public/browser/browser_child_process_host.h"
37#include "content/public/browser/child_process_data.h"
[email protected]4734d0b2011-12-03 07:10:4438#include "content/public/common/child_process_host.h"
[email protected]d032f492009-09-29 00:33:4639#include "ipc/ipc_switches.h"
[email protected]1d8a3d1f2011-02-19 07:11:5240#include "native_client/src/shared/imc/nacl_imc.h"
[email protected]87f35592012-04-08 00:49:1641#include "net/base/net_util.h"
[email protected]d032f492009-09-29 00:33:4642
[email protected]d032f492009-09-29 00:33:4643#if defined(OS_POSIX)
[email protected]a82af392012-02-24 04:40:2044#include <fcntl.h>
45
[email protected]d032f492009-09-29 00:33:4646#include "ipc/ipc_channel_posix.h"
[email protected]4bdde602010-06-16 03:17:3547#elif defined(OS_WIN)
[email protected]a82af392012-02-24 04:40:2048#include <windows.h>
49
[email protected]b39c6d92012-01-31 16:38:4150#include "base/threading/thread.h"
51#include "base/process_util.h"
[email protected]4c65fb632012-04-27 00:42:2552#include "base/win/scoped_handle.h"
[email protected]4bdde602010-06-16 03:17:3553#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
[email protected]e4f6eb0232012-04-17 00:47:5054#include "content/public/common/sandbox_init.h"
[email protected]b39c6d92012-01-31 16:38:4155#include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
[email protected]d032f492009-09-29 00:33:4656#endif
57
[email protected]631bb742011-11-02 11:29:3958using content::BrowserThread;
[email protected]4967f792012-01-20 22:14:4059using content::ChildProcessData;
[email protected]4734d0b2011-12-03 07:10:4460using content::ChildProcessHost;
[email protected]631bb742011-11-02 11:29:3961
[email protected]646e15552012-04-06 22:01:0462namespace {
63
64#if defined(OS_WIN)
65bool RunningOnWOW64() {
66 return (base::win::OSInfo::GetInstance()->wow64_status() ==
67 base::win::OSInfo::WOW64_ENABLED);
68}
69#endif
70
71// Determine the name of the IRT file based on the architecture.
72#define NACL_IRT_FILE_NAME(arch_string) \
73 (FILE_PATH_LITERAL("nacl_irt_") \
74 FILE_PATH_LITERAL(arch_string) \
75 FILE_PATH_LITERAL(".nexe"))
76
77const FilePath::StringType NaClIrtName() {
78#if defined(ARCH_CPU_X86_FAMILY)
79#if defined(ARCH_CPU_X86_64)
80 bool is64 = true;
81#elif defined(OS_WIN)
82 bool is64 = RunningOnWOW64();
83#else
84 bool is64 = false;
85#endif
86 return is64 ? NACL_IRT_FILE_NAME("x86_64") : NACL_IRT_FILE_NAME("x86_32");
87#elif defined(ARCH_CPU_ARMEL)
88 // TODO(mcgrathr): Eventually we'll need to distinguish arm32 vs thumb2.
89 // That may need to be based on the actual nexe rather than a static
90 // choice, which would require substantial refactoring.
91 return NACL_IRT_FILE_NAME("arm");
92#else
93#error Add support for your architecture to NaCl IRT file selection
94#endif
95}
96
97void SetCloseOnExec(nacl::Handle fd) {
98#if defined(OS_POSIX)
99 int flags = fcntl(fd, F_GETFD);
100 CHECK_NE(flags, -1);
101 int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
102 CHECK_EQ(rc, 0);
103#endif
104}
105
[email protected]00d99542012-04-17 22:48:02106bool ShareHandleToSelLdr(
[email protected]646e15552012-04-06 22:01:04107 base::ProcessHandle processh,
108 nacl::Handle sourceh,
109 bool close_source,
110 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
111#if defined(OS_WIN)
112 HANDLE channel;
113 int flags = DUPLICATE_SAME_ACCESS;
114 if (close_source)
115 flags |= DUPLICATE_CLOSE_SOURCE;
116 if (!DuplicateHandle(GetCurrentProcess(),
117 reinterpret_cast<HANDLE>(sourceh),
118 processh,
119 &channel,
120 0, // Unused given DUPLICATE_SAME_ACCESS.
121 FALSE,
122 flags)) {
[email protected]09afc2e2012-04-10 17:29:03123 DLOG(ERROR) << "DuplicateHandle() failed";
[email protected]646e15552012-04-06 22:01:04124 return false;
125 }
126 handles_for_sel_ldr->push_back(
127 reinterpret_cast<nacl::FileDescriptor>(channel));
128#else
129 nacl::FileDescriptor channel;
130 channel.fd = sourceh;
131 channel.auto_close = close_source;
132 handles_for_sel_ldr->push_back(channel);
133#endif
134 return true;
135}
136
137// NaClBrowser -----------------------------------------------------------------
138
139// Represents shared state for all NaClProcessHost objects in the browser.
140// Currently this just handles holding onto the file descriptor for the IRT.
141class NaClBrowser {
142 public:
143 static NaClBrowser* GetInstance() {
144 return Singleton<NaClBrowser>::get();
145 }
146
147 bool IrtAvailable() const {
148 return irt_platform_file_ != base::kInvalidPlatformFileValue;
149 }
150
151 base::PlatformFile IrtFile() const {
152 CHECK_NE(irt_platform_file_, base::kInvalidPlatformFileValue);
153 return irt_platform_file_;
154 }
155
156 // Asynchronously attempt to get the IRT open.
157 bool EnsureIrtAvailable();
158
159 // Make sure the IRT gets opened and follow up with the reply when it's ready.
160 bool MakeIrtAvailable(const base::Closure& reply);
161
162 // Path to IRT. Available even before IRT is loaded.
163 const FilePath& GetIrtFilePath();
164
165 // Get the key used for HMACing validation signatures. This should be a
166 // string of cryptographically secure random bytes.
167 const std::string& GetValidatorCacheKey() const {
168 return validator_cache_key_;
169 }
170
171 // Is the validation signature in the database?
172 bool QueryKnownToValidate(const std::string& signature);
173
174 // Put the validation signature in the database.
175 void SetKnownToValidate(const std::string& signature);
176
177 private:
178 friend struct DefaultSingletonTraits<NaClBrowser>;
179
180 NaClBrowser()
181 : irt_platform_file_(base::kInvalidPlatformFileValue),
182 irt_filepath_(),
183 // For the moment, choose an arbitrary cache size.
184 validation_cache_(200),
185 // TODO(ncbray) persist this key along with the cache.
186 // Key size is equal to the block size (not the digest size) of SHA256.
187 validator_cache_key_(base::RandBytesAsString(64)) {
188 InitIrtFilePath();
189 }
190
191 ~NaClBrowser() {
192 if (irt_platform_file_ != base::kInvalidPlatformFileValue)
193 base::ClosePlatformFile(irt_platform_file_);
194 }
195
196 void InitIrtFilePath();
197
198 void OpenIrtLibraryFile();
199
200 static void DoOpenIrtLibraryFile() {
201 GetInstance()->OpenIrtLibraryFile();
202 }
203
204 base::PlatformFile irt_platform_file_;
205
206 FilePath irt_filepath_;
207
208 typedef base::HashingMRUCache<std::string, bool> ValidationCacheType;
209 ValidationCacheType validation_cache_;
210
211 std::string validator_cache_key_;
212
213 DISALLOW_COPY_AND_ASSIGN(NaClBrowser);
214};
215
216// Attempt to ensure the IRT will be available when we need it, but don't wait.
217bool NaClBrowser::EnsureIrtAvailable() {
218 if (IrtAvailable())
219 return true;
220
221 return BrowserThread::PostTask(
222 BrowserThread::FILE, FROM_HERE,
223 base::Bind(&NaClBrowser::DoOpenIrtLibraryFile));
224}
225
226// We really need the IRT to be available now, so make sure that it is.
227// When it's ready, we'll run the reply closure.
228bool NaClBrowser::MakeIrtAvailable(const base::Closure& reply) {
229 return BrowserThread::PostTaskAndReply(
230 BrowserThread::FILE, FROM_HERE,
231 base::Bind(&NaClBrowser::DoOpenIrtLibraryFile), reply);
232}
233
234const FilePath& NaClBrowser::GetIrtFilePath() {
235 return irt_filepath_;
236}
237
238bool NaClBrowser::QueryKnownToValidate(const std::string& signature) {
239 bool result = false;
240 ValidationCacheType::iterator iter = validation_cache_.Get(signature);
241 if (iter != validation_cache_.end()) {
242 result = iter->second;
243 }
244 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Query",
245 result ? 1 : 0, 2);
246 return result;
247}
248
249void NaClBrowser::SetKnownToValidate(const std::string& signature) {
250 validation_cache_.Put(signature, true);
251 // The number of sets should be equal to the number of cache misses, minus
252 // validation failures and successful validations where stubout occurs.
253 // Bucket zero is reserved for future use.
254 UMA_HISTOGRAM_ENUMERATION("NaCl.ValidationCache.Set", 1, 2);
255}
256
257void NaClBrowser::InitIrtFilePath() {
258 // Allow the IRT library to be overridden via an environment
259 // variable. This allows the NaCl/Chromium integration bot to
260 // specify a newly-built IRT rather than using a prebuilt one
261 // downloaded via Chromium's DEPS file. We use the same environment
262 // variable that the standalone NaCl PPAPI plugin accepts.
263 const char* irt_path_var = getenv("NACL_IRT_LIBRARY");
264 if (irt_path_var != NULL) {
265 FilePath::StringType path_string(
266 irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0')));
267 irt_filepath_ = FilePath(path_string);
268 } else {
269 FilePath plugin_dir;
270 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) {
[email protected]09afc2e2012-04-10 17:29:03271 DLOG(ERROR) << "Failed to locate the plugins directory";
[email protected]646e15552012-04-06 22:01:04272 return;
273 }
274
275 irt_filepath_ = plugin_dir.Append(NaClIrtName());
276 }
277}
278
279// This only ever runs on the BrowserThread::FILE thread.
280// If multiple tasks are posted, the later ones are no-ops.
281void NaClBrowser::OpenIrtLibraryFile() {
282 if (irt_platform_file_ != base::kInvalidPlatformFileValue)
283 // We've already run.
284 return;
285
286 base::PlatformFileError error_code;
287 irt_platform_file_ = base::CreatePlatformFile(irt_filepath_,
288 base::PLATFORM_FILE_OPEN |
289 base::PLATFORM_FILE_READ,
290 NULL,
291 &error_code);
292 if (error_code != base::PLATFORM_FILE_OK) {
293 LOG(ERROR) << "Failed to open NaCl IRT file \""
294 << irt_filepath_.LossyDisplayName()
295 << "\": " << error_code;
296 }
297}
298
299} // namespace
300
301// DebugContext ----------------------------------------------------------------
302
[email protected]b39c6d92012-01-31 16:38:41303#if defined(OS_WIN)
304class NaClProcessHost::DebugContext
305 : public base::RefCountedThreadSafe<NaClProcessHost::DebugContext> {
306 public:
307 DebugContext()
[email protected]8236f852012-04-05 10:24:31308 : can_send_start_msg_(false) {
[email protected]b39c6d92012-01-31 16:38:41309 }
310
311 ~DebugContext() {
312 }
313
314 void AttachDebugger(int pid, base::ProcessHandle process);
315
316 // 6 methods below must be called on Browser::IO thread.
317 void SetStartMessage(IPC::Message* start_msg);
[email protected]8236f852012-04-05 10:24:31318 void SetNaClProcessHost(base::WeakPtr<NaClProcessHost> nacl_process_host);
[email protected]b39c6d92012-01-31 16:38:41319 void SetDebugThread(base::Thread* thread_);
320
321 // Start message is sent from 2 flows of execution. The first flow is
322 // NaClProcessHost::SendStart. The second flow is
323 // NaClProcessHost::OnChannelConnected and
324 // NaClProcessHost::DebugContext::AttachThread. The message itself is created
325 // by first flow. But the moment it can be sent is determined by second flow.
326 // So first flow executes SetStartMessage and SendStartMessage while second
327 // flow uses AllowAndSendStartMessage to either send potentially pending
328 // start message or set the flag that allows the first flow to do this.
329
330 // Clears the flag that prevents sending start message.
331 void AllowToSendStartMsg();
332 // Send start message to the NaCl process or do nothing if message is not
333 // set or not allowed to be send. If message is sent, it is cleared and
334 // repeated calls do nothing.
335 void SendStartMessage();
336 // Clear the flag that prevents further sending start message and send start
337 // message if it is set.
338 void AllowAndSendStartMessage();
339 private:
340 void StopThread();
341 // These 4 fields are accessed only from Browser::IO thread.
342 scoped_ptr<base::Thread> thread_;
343 scoped_ptr<IPC::Message> start_msg_;
344 // Debugger is attached or exception handling is not switched on.
345 // This means that start message can be sent to the NaCl process.
346 bool can_send_start_msg_;
[email protected]8236f852012-04-05 10:24:31347 base::WeakPtr<NaClProcessHost> nacl_process_host_;
[email protected]b39c6d92012-01-31 16:38:41348};
349
350void NaClProcessHost::DebugContext::AttachDebugger(
351 int pid, base::ProcessHandle process) {
352 BOOL attached;
353 DWORD exit_code;
354 attached = DebugActiveProcess(pid);
355 if (!attached) {
[email protected]09afc2e2012-04-10 17:29:03356 DLOG(ERROR) << "Failed to connect to the process";
[email protected]b39c6d92012-01-31 16:38:41357 }
358 BrowserThread::PostTask(
359 BrowserThread::IO, FROM_HERE,
360 base::Bind(
361 &NaClProcessHost::DebugContext::AllowAndSendStartMessage, this));
362 if (attached) {
363 // debug the process
364 NaClDebugLoop(process, &exit_code);
365 base::CloseProcessHandle(process);
366 }
367 BrowserThread::PostTask(
368 BrowserThread::IO, FROM_HERE,
369 base::Bind(&NaClProcessHost::DebugContext::StopThread, this));
370}
371
372void NaClProcessHost::DebugContext::SetStartMessage(IPC::Message* start_msg) {
373 start_msg_.reset(start_msg);
374}
375
[email protected]8236f852012-04-05 10:24:31376void NaClProcessHost::DebugContext::SetNaClProcessHost(
377 base::WeakPtr<NaClProcessHost> nacl_process_host) {
378 nacl_process_host_ = nacl_process_host;
[email protected]b39c6d92012-01-31 16:38:41379}
380
381void NaClProcessHost::DebugContext::SetDebugThread(base::Thread* thread) {
382 thread_.reset(thread);
383}
384
385void NaClProcessHost::DebugContext::AllowToSendStartMsg() {
386 can_send_start_msg_ = true;
387}
388
389void NaClProcessHost::DebugContext::SendStartMessage() {
390 if (start_msg_.get() && can_send_start_msg_) {
[email protected]8236f852012-04-05 10:24:31391 if (nacl_process_host_) {
392 if (!nacl_process_host_->Send(start_msg_.release())) {
[email protected]09afc2e2012-04-10 17:29:03393 DLOG(ERROR) << "Failed to send start message";
[email protected]b39c6d92012-01-31 16:38:41394 }
395 }
396 }
397}
398
399void NaClProcessHost::DebugContext::AllowAndSendStartMessage() {
400 AllowToSendStartMsg();
401 SendStartMessage();
402}
403
404void NaClProcessHost::DebugContext::StopThread() {
405 thread_->Stop();
406 thread_.reset();
407}
408#endif
409
[email protected]1d8a3d1f2011-02-19 07:11:52410struct NaClProcessHost::NaClInternal {
411 std::vector<nacl::Handle> sockets_for_renderer;
412 std::vector<nacl::Handle> sockets_for_sel_ldr;
413};
414
[email protected]646e15552012-04-06 22:01:04415// -----------------------------------------------------------------------------
[email protected]773ebb92011-11-15 19:06:52416
[email protected]87f35592012-04-08 00:49:16417NaClProcessHost::NaClProcessHost(const GURL& manifest_url)
418 : manifest_url_(manifest_url),
[email protected]a575da52012-03-22 13:08:36419#if defined(OS_WIN)
420 process_launched_by_broker_(false),
[email protected]5b974952012-04-05 18:18:23421#elif defined(OS_LINUX)
422 wait_for_nacl_gdb_(false),
[email protected]a575da52012-03-22 13:08:36423#endif
424 reply_msg_(NULL),
[email protected]1d8a3d1f2011-02-19 07:11:52425 internal_(new NaClInternal()),
[email protected]5ca93be2012-03-21 20:04:06426 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
427 enable_exception_handling_(false) {
[email protected]4967f792012-01-20 22:14:40428 process_.reset(content::BrowserChildProcessHost::Create(
429 content::PROCESS_TYPE_NACL_LOADER, this));
[email protected]87f35592012-04-08 00:49:16430
431 // Set the display name so the user knows what plugin the process is running.
432 // We aren't on the UI thread so getting the pref locale for language
433 // formatting isn't possible, so IDN will be lost, but this is probably OK
434 // for this use case.
435 process_->SetName(net::FormatUrl(manifest_url_, std::string()));
[email protected]5ca93be2012-03-21 20:04:06436
437 // We allow untrusted hardware exception handling to be enabled via
438 // an env var for consistency with the standalone build of NaCl.
439 if (CommandLine::ForCurrentProcess()->HasSwitch(
440 switches::kEnableNaClExceptionHandling) ||
441 getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
442 enable_exception_handling_ = true;
[email protected]b39c6d92012-01-31 16:38:41443#if defined(OS_WIN)
[email protected]fb335fe2012-03-24 18:11:38444 debug_context_ = new DebugContext();
[email protected]b39c6d92012-01-31 16:38:41445#endif
[email protected]5ca93be2012-03-21 20:04:06446 }
[email protected]d032f492009-09-29 00:33:46447}
448
[email protected]fb1277e82009-11-21 20:32:30449NaClProcessHost::~NaClProcessHost() {
[email protected]4cb43102011-12-02 20:24:49450 int exit_code;
[email protected]4967f792012-01-20 22:14:40451 process_->GetTerminationStatus(&exit_code);
[email protected]4cb43102011-12-02 20:24:49452 std::string message =
453 base::StringPrintf("NaCl process exited with status %i (0x%x)",
454 exit_code, exit_code);
455 if (exit_code == 0) {
456 LOG(INFO) << message;
457 } else {
458 LOG(ERROR) << message;
459 }
460
[email protected]1d8a3d1f2011-02-19 07:11:52461 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]909c2402011-05-09 11:39:04462 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) {
[email protected]09afc2e2012-04-10 17:29:03463 NOTREACHED() << "nacl::Close() failed";
[email protected]909c2402011-05-09 11:39:04464 }
[email protected]c47ec402010-07-29 10:20:49465 }
[email protected]1d8a3d1f2011-02-19 07:11:52466 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]909c2402011-05-09 11:39:04467 if (nacl::Close(internal_->sockets_for_sel_ldr[i]) != 0) {
[email protected]09afc2e2012-04-10 17:29:03468 NOTREACHED() << "nacl::Close() failed";
[email protected]909c2402011-05-09 11:39:04469 }
[email protected]c47ec402010-07-29 10:20:49470 }
471
[email protected]909c2402011-05-09 11:39:04472 if (reply_msg_) {
473 // The process failed to launch for some reason.
474 // Don't keep the renderer hanging.
475 reply_msg_->set_reply_error();
476 chrome_render_message_filter_->Send(reply_msg_);
477 }
[email protected]b39c6d92012-01-31 16:38:41478#if defined(OS_WIN)
[email protected]a575da52012-03-22 13:08:36479 if (process_launched_by_broker_) {
480 NaClBrokerService::GetInstance()->OnLoaderDied();
[email protected]5ca93be2012-03-21 20:04:06481 }
[email protected]b39c6d92012-01-31 16:38:41482#endif
[email protected]fb1277e82009-11-21 20:32:30483}
484
[email protected]773ebb92011-11-15 19:06:52485// This is called at browser startup.
486// static
487void NaClProcessHost::EarlyStartup() {
488#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
489 // Open the IRT file early to make sure that it isn't replaced out from
490 // under us by autoupdate.
491 NaClBrowser::GetInstance()->EnsureIrtAvailable();
492#endif
493}
494
[email protected]a575da52012-03-22 13:08:36495void NaClProcessHost::Launch(
[email protected]92d56412011-03-24 20:53:52496 ChromeRenderMessageFilter* chrome_render_message_filter,
497 int socket_count,
[email protected]8f42b4d2012-03-24 14:12:33498 IPC::Message* reply_msg,
499 scoped_refptr<ExtensionInfoMap> extension_info_map) {
[email protected]a575da52012-03-22 13:08:36500 chrome_render_message_filter_ = chrome_render_message_filter;
501 reply_msg_ = reply_msg;
[email protected]8f42b4d2012-03-24 14:12:33502 extension_info_map_ = extension_info_map;
[email protected]a575da52012-03-22 13:08:36503
[email protected]c47ec402010-07-29 10:20:49504 // Place an arbitrary limit on the number of sockets to limit
505 // exposure in case the renderer is compromised. We can increase
506 // this if necessary.
507 if (socket_count > 8) {
[email protected]a575da52012-03-22 13:08:36508 delete this;
509 return;
[email protected]c47ec402010-07-29 10:20:49510 }
511
[email protected]773ebb92011-11-15 19:06:52512 // Start getting the IRT open asynchronously while we launch the NaCl process.
[email protected]09afc2e2012-04-10 17:29:03513 // We'll make sure this actually finished in StartWithLaunchedProcess, below.
[email protected]773ebb92011-11-15 19:06:52514 if (!NaClBrowser::GetInstance()->EnsureIrtAvailable()) {
[email protected]09afc2e2012-04-10 17:29:03515 DLOG(ERROR) << "Cannot launch NaCl process after IRT file open failed";
[email protected]a575da52012-03-22 13:08:36516 delete this;
517 return;
[email protected]773ebb92011-11-15 19:06:52518 }
519
[email protected]c47ec402010-07-29 10:20:49520 // Rather than creating a socket pair in the renderer, and passing
521 // one side through the browser to sel_ldr, socket pairs are created
522 // in the browser and then passed to the renderer and sel_ldr.
523 //
524 // This is mainly for the benefit of Windows, where sockets cannot
525 // be passed in messages, but are copied via DuplicateHandle().
526 // This means the sandboxed renderer cannot send handles to the
527 // browser process.
528
529 for (int i = 0; i < socket_count; i++) {
530 nacl::Handle pair[2];
531 // Create a connected socket
[email protected]a575da52012-03-22 13:08:36532 if (nacl::SocketPair(pair) == -1) {
533 delete this;
534 return;
535 }
[email protected]1d8a3d1f2011-02-19 07:11:52536 internal_->sockets_for_renderer.push_back(pair[0]);
537 internal_->sockets_for_sel_ldr.push_back(pair[1]);
[email protected]c47ec402010-07-29 10:20:49538 SetCloseOnExec(pair[0]);
539 SetCloseOnExec(pair[1]);
540 }
[email protected]d032f492009-09-29 00:33:46541
542 // Launch the process
[email protected]fb1277e82009-11-21 20:32:30543 if (!LaunchSelLdr()) {
[email protected]a575da52012-03-22 13:08:36544 delete this;
[email protected]d032f492009-09-29 00:33:46545 }
[email protected]d032f492009-09-29 00:33:46546}
[email protected]646e15552012-04-06 22:01:04547
[email protected]5b974952012-04-05 18:18:23548#if defined(OS_WIN)
[email protected]646e15552012-04-06 22:01:04549void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
550 // Set process handle, if it was not set previously.
551 // This is needed when NaCl process is launched with nacl-gdb.
552 if (process_->GetData().handle == base::kNullProcessHandle) {
553 base::ProcessHandle process;
554 DCHECK(!CommandLine::ForCurrentProcess()->GetSwitchValuePath(
555 switches::kNaClGdb).empty());
556 if (base::OpenProcessHandleWithAccess(
557 peer_pid,
558 base::kProcessAccessDuplicateHandle |
559 base::kProcessAccessQueryInformation |
560 base::kProcessAccessWaitForTermination,
561 &process)) {
562 process_->SetHandle(process);
[email protected]09afc2e2012-04-10 17:29:03563 if (!StartWithLaunchedProcess()) {
564 delete this;
565 return;
566 }
[email protected]646e15552012-04-06 22:01:04567 } else {
[email protected]09afc2e2012-04-10 17:29:03568 DLOG(ERROR) << "Failed to get process handle";
[email protected]646e15552012-04-06 22:01:04569 }
570 }
571 if (debug_context_ == NULL) {
572 return;
573 }
574 debug_context_->SetNaClProcessHost(weak_factory_.GetWeakPtr());
575 if (RunningOnWOW64()) {
[email protected]4c65fb632012-04-27 00:42:25576 base::win::ScopedHandle process_handle;
577 // We cannot use process_->GetData().handle because it does not
578 // have the necessary access rights. We open the new handle here
579 // rather than in the NaCl broker process in case the NaCl loader
580 // process dies before the NaCl broker process receives the
581 // message we send. The debug exception handler uses
582 // DebugActiveProcess() to attach, but this takes a PID. We need
583 // to prevent the NaCl loader's PID from being reused before
584 // DebugActiveProcess() is called, and holding a process handle
585 // open achieves this.
586 if (!base::OpenProcessHandleWithAccess(
587 peer_pid,
588 base::kProcessAccessQueryInformation |
589 base::kProcessAccessSuspendResume |
590 base::kProcessAccessTerminate |
591 base::kProcessAccessVMOperation |
592 base::kProcessAccessVMRead |
593 base::kProcessAccessVMWrite |
594 base::kProcessAccessWaitForTermination,
595 process_handle.Receive())) {
596 LOG(ERROR) << "Failed to get process handle";
[email protected]646e15552012-04-06 22:01:04597 debug_context_->AllowAndSendStartMessage();
[email protected]4c65fb632012-04-27 00:42:25598 } else {
599 if (!NaClBrokerService::GetInstance()->LaunchDebugExceptionHandler(
600 weak_factory_.GetWeakPtr(), peer_pid, process_handle)) {
601 debug_context_->AllowAndSendStartMessage();
602 }
[email protected]646e15552012-04-06 22:01:04603 }
604 } else {
605 // Start new thread for debug loop
606 // We can't use process_->GetData().handle because it doesn't have necessary
607 // access rights.
608 base::ProcessHandle process;
609 if (!base::OpenProcessHandleWithAccess(
610 peer_pid,
611 base::kProcessAccessQueryInformation |
612 base::kProcessAccessSuspendResume |
613 base::kProcessAccessTerminate |
614 base::kProcessAccessVMOperation |
615 base::kProcessAccessVMRead |
616 base::kProcessAccessVMWrite |
617 base::kProcessAccessWaitForTermination,
618 &process)) {
[email protected]09afc2e2012-04-10 17:29:03619 DLOG(ERROR) << "Failed to open the process";
[email protected]646e15552012-04-06 22:01:04620 debug_context_->AllowAndSendStartMessage();
621 return;
622 }
623 base::Thread* dbg_thread = new base::Thread("Debug thread");
624 if (!dbg_thread->Start()) {
[email protected]09afc2e2012-04-10 17:29:03625 DLOG(ERROR) << "Debug thread not started";
[email protected]646e15552012-04-06 22:01:04626 debug_context_->AllowAndSendStartMessage();
627 base::CloseProcessHandle(process);
628 return;
629 }
630 debug_context_->SetDebugThread(dbg_thread);
631 // System can not reallocate pid until we close process handle. So using
632 // pid in different thread is fine.
633 dbg_thread->message_loop()->PostTask(FROM_HERE,
634 base::Bind(&NaClProcessHost::DebugContext::AttachDebugger,
635 debug_context_, peer_pid, process));
636 }
637}
638#else
639void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
640}
641#endif
642
643#if defined(OS_WIN)
644void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
645 process_launched_by_broker_ = true;
646 process_->SetHandle(handle);
[email protected]09afc2e2012-04-10 17:29:03647 if (!StartWithLaunchedProcess())
648 delete this;
[email protected]646e15552012-04-06 22:01:04649}
650
651void NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker() {
652 debug_context_->AllowAndSendStartMessage();
653}
654#endif
655
656// Needed to handle sync messages in OnMessageRecieved.
657bool NaClProcessHost::Send(IPC::Message* msg) {
658 return process_->Send(msg);
659}
660
661#if defined(OS_WIN)
662scoped_ptr<CommandLine> NaClProcessHost::GetCommandForLaunchWithGdb(
[email protected]8f42b4d2012-03-24 14:12:33663 const FilePath& nacl_gdb,
[email protected]5b974952012-04-05 18:18:23664 CommandLine* line) {
[email protected]31a665e72012-03-11 12:37:46665 CommandLine* cmd_line = new CommandLine(nacl_gdb);
666 // We can't use PrependWrapper because our parameters contain spaces.
667 cmd_line->AppendArg("--eval-command");
668 const FilePath::StringType& irt_path =
669 NaClBrowser::GetInstance()->GetIrtFilePath().value();
670 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
[email protected]5b974952012-04-05 18:18:23671 FilePath manifest_path = GetManifestPath();
[email protected]8f42b4d2012-03-24 14:12:33672 if (!manifest_path.empty()) {
673 cmd_line->AppendArg("--eval-command");
674 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
675 manifest_path.value());
676 }
[email protected]31a665e72012-03-11 12:37:46677 cmd_line->AppendArg("--args");
678 const CommandLine::StringVector& argv = line->argv();
679 for (size_t i = 0; i < argv.size(); i++) {
680 cmd_line->AppendArgNative(argv[i]);
681 }
682 return scoped_ptr<CommandLine>(cmd_line);
683}
[email protected]5b974952012-04-05 18:18:23684#elif defined(OS_LINUX)
685namespace {
686class NaClGdbWatchDelegate : public MessageLoopForIO::Watcher {
687 public:
688 // fd_write_ is used by nacl-gdb via /proc/browser_PID/fd/fd_write_
689 NaClGdbWatchDelegate(int fd_read, int fd_write,
690 const base::Closure& reply)
691 : fd_read_(fd_read),
692 fd_write_(fd_write),
693 reply_(reply) {}
694
695 ~NaClGdbWatchDelegate() {
696 if (HANDLE_EINTR(close(fd_read_)) != 0)
697 DLOG(ERROR) << "close(fd_read_) failed";
698 if (HANDLE_EINTR(close(fd_write_)) != 0)
699 DLOG(ERROR) << "close(fd_write_) failed";
700 }
701
702 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
703 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
704
705 private:
706 int fd_read_;
707 int fd_write_;
708 base::Closure reply_;
709};
710
711void NaClGdbWatchDelegate::OnFileCanReadWithoutBlocking(int fd) {
712 char buf;
713 if (HANDLE_EINTR(read(fd_read_, &buf, 1)) != 1 || buf != '\0')
714 LOG(ERROR) << "Failed to sync with nacl-gdb";
715 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, reply_);
716}
717} // namespace
718
719bool NaClProcessHost::LaunchNaClGdb(base::ProcessId pid) {
720 CommandLine::StringType nacl_gdb =
721 CommandLine::ForCurrentProcess()->GetSwitchValueNative(
722 switches::kNaClGdb);
723 CommandLine::StringVector argv;
724 // We don't support spaces inside arguments in --nacl-gdb switch.
725 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
726 CommandLine cmd_line(argv);
727 cmd_line.AppendArg("--eval-command");
728 const FilePath::StringType& irt_path =
729 NaClBrowser::GetInstance()->GetIrtFilePath().value();
730 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
731 FilePath manifest_path = GetManifestPath();
732 if (!manifest_path.empty()) {
733 cmd_line.AppendArg("--eval-command");
734 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
735 manifest_path.value());
736 }
737 cmd_line.AppendArg("--eval-command");
738 cmd_line.AppendArg("attach " + base::IntToString(pid));
739 int fds[2];
740 if (pipe(fds) != 0)
741 return false;
742 // Tell the debugger to send a byte to the writable end of the pipe.
743 // We use a file descriptor in our process because the debugger will be
744 // typically launched in a separate terminal, and a lot of terminals close all
745 // file descriptors before launching external programs.
746 cmd_line.AppendArg("--eval-command");
747 cmd_line.AppendArg("dump binary value /proc/" +
748 base::IntToString(base::GetCurrentProcId()) +
749 "/fd/" + base::IntToString(fds[1]) + " (char)0");
750 // wait on fds[0]
751 // If the debugger crashes before attaching to the NaCl process, the user can
752 // release resources by terminating the NaCl loader in Chrome Task Manager.
753 nacl_gdb_watcher_delegate_.reset(
754 new NaClGdbWatchDelegate(
755 fds[0], fds[1],
756 base::Bind(&NaClProcessHost::OnNaClGdbAttached,
757 weak_factory_.GetWeakPtr())));
758 MessageLoopForIO::current()->WatchFileDescriptor(
759 fds[0],
760 true,
761 MessageLoopForIO::WATCH_READ,
762 &nacl_gdb_watcher_,
763 nacl_gdb_watcher_delegate_.get());
764 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
765}
766
767void NaClProcessHost::OnNaClGdbAttached() {
768 wait_for_nacl_gdb_ = false;
769 nacl_gdb_watcher_.StopWatchingFileDescriptor();
770 nacl_gdb_watcher_delegate_.reset();
771 OnProcessLaunched();
772}
773#endif
774
775FilePath NaClProcessHost::GetManifestPath() {
[email protected]5b974952012-04-05 18:18:23776 const Extension* extension = extension_info_map_->extensions()
[email protected]87f35592012-04-08 00:49:16777 .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url_));
778 if (extension != NULL && manifest_url_.SchemeIs(chrome::kExtensionScheme)) {
779 std::string path = manifest_url_.path();
[email protected]5b974952012-04-05 18:18:23780 TrimString(path, "/", &path); // Remove first slash
781 return extension->path().AppendASCII(path);
782 }
783 return FilePath();
784}
[email protected]31a665e72012-03-11 12:37:46785
[email protected]fb1277e82009-11-21 20:32:30786bool NaClProcessHost::LaunchSelLdr() {
[email protected]4967f792012-01-20 22:14:40787 std::string channel_id = process_->GetHost()->CreateChannel();
[email protected]4734d0b2011-12-03 07:10:44788 if (channel_id.empty())
[email protected]d032f492009-09-29 00:33:46789 return false;
790
[email protected]e3fc75a2011-05-05 08:20:42791 CommandLine::StringType nacl_loader_prefix;
792#if defined(OS_POSIX)
793 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
794 switches::kNaClLoaderCmdPrefix);
795#endif // defined(OS_POSIX)
796
[email protected]d032f492009-09-29 00:33:46797 // Build command line for nacl.
[email protected]8c40f322011-08-24 03:33:36798
799#if defined(OS_MACOSX)
800 // The Native Client process needs to be able to allocate a 1GB contiguous
801 // region to use as the client environment's virtual address space. ASLR
802 // (PIE) interferes with this by making it possible that no gap large enough
803 // to accomodate this request will exist in the child process' address
804 // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
805 // http://code.google.com/p/nativeclient/issues/detail?id=2043.
[email protected]4cb43102011-12-02 20:24:49806 int flags = ChildProcessHost::CHILD_NO_PIE;
[email protected]8c40f322011-08-24 03:33:36807#elif defined(OS_LINUX)
[email protected]4cb43102011-12-02 20:24:49808 int flags = nacl_loader_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
809 ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36810#else
[email protected]4cb43102011-12-02 20:24:49811 int flags = ChildProcessHost::CHILD_NORMAL;
[email protected]8c40f322011-08-24 03:33:36812#endif
813
[email protected]4cb43102011-12-02 20:24:49814 FilePath exe_path = ChildProcessHost::GetChildPath(flags);
[email protected]fb1277e82009-11-21 20:32:30815 if (exe_path.empty())
[email protected]d032f492009-09-29 00:33:46816 return false;
817
[email protected]31a665e72012-03-11 12:37:46818#if defined(OS_WIN)
819 // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
820 if (RunningOnWOW64()) {
821 FilePath module_path;
822 if (!PathService::Get(base::FILE_MODULE, &module_path))
823 return false;
824 exe_path = module_path.DirName().Append(chrome::kNaClAppName);
825 }
826#endif
827
[email protected]33a05af2012-03-02 18:15:51828 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
829 nacl::CopyNaClCommandLineArguments(cmd_line.get());
[email protected]599e6642010-01-27 18:52:13830
[email protected]05076ba22010-07-30 05:59:57831 cmd_line->AppendSwitchASCII(switches::kProcessType,
832 switches::kNaClLoaderProcess);
[email protected]4734d0b2011-12-03 07:10:44833 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
[email protected]93156cec2011-09-12 21:14:44834 if (logging::DialogsAreSuppressed())
835 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
[email protected]d032f492009-09-29 00:33:46836
[email protected]e3fc75a2011-05-05 08:20:42837 if (!nacl_loader_prefix.empty())
838 cmd_line->PrependWrapper(nacl_loader_prefix);
839
[email protected]31a665e72012-03-11 12:37:46840 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
841 switches::kNaClGdb);
842 if (!nacl_gdb.empty()) {
[email protected]5b974952012-04-05 18:18:23843#if defined(OS_WIN)
[email protected]31a665e72012-03-11 12:37:46844 cmd_line->AppendSwitch(switches::kNoSandbox);
845 scoped_ptr<CommandLine> gdb_cmd_line(
[email protected]646e15552012-04-06 22:01:04846 GetCommandForLaunchWithGdb(nacl_gdb, cmd_line.get()));
[email protected]31a665e72012-03-11 12:37:46847 // We can't use process_->Launch() because OnProcessLaunched will be called
848 // with process_->GetData().handle filled by handle of gdb process. This
849 // handle will be used to duplicate handles for NaCl process and as
850 // a result NaCl process will not be able to use them.
851 //
852 // So we don't fill process_->GetData().handle and wait for
853 // OnChannelConnected to get handle of NaCl process from its pid. Then we
854 // call OnProcessLaunched.
855 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL);
[email protected]5b974952012-04-05 18:18:23856#elif defined(OS_LINUX)
857 wait_for_nacl_gdb_ = true;
858#endif
[email protected]31a665e72012-03-11 12:37:46859 }
860
[email protected]103607e2010-02-01 18:57:09861 // On Windows we might need to start the broker process to launch a new loader
[email protected]d032f492009-09-29 00:33:46862#if defined(OS_WIN)
[email protected]773ebb92011-11-15 19:06:52863 if (RunningOnWOW64()) {
[email protected]26b3c002012-04-26 19:38:34864 return NaClBrokerService::GetInstance()->LaunchLoader(
865 weak_factory_.GetWeakPtr(), channel_id);
[email protected]4bdde602010-06-16 03:17:35866 } else {
[email protected]33a05af2012-03-02 18:15:51867 process_->Launch(FilePath(), cmd_line.release());
[email protected]4bdde602010-06-16 03:17:35868 }
[email protected]103607e2010-02-01 18:57:09869#elif defined(OS_POSIX)
[email protected]4967f792012-01-20 22:14:40870 process_->Launch(nacl_loader_prefix.empty(), // use_zygote
[email protected]a82af392012-02-24 04:40:20871 base::EnvironmentVector(),
[email protected]33a05af2012-03-02 18:15:51872 cmd_line.release());
[email protected]103607e2010-02-01 18:57:09873#endif
[email protected]d032f492009-09-29 00:33:46874
[email protected]fb1277e82009-11-21 20:32:30875 return true;
[email protected]d032f492009-09-29 00:33:46876}
877
[email protected]646e15552012-04-06 22:01:04878bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
879 bool handled = true;
880 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
881 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
882 OnQueryKnownToValidate)
883 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
884 OnSetKnownToValidate)
885 IPC_MESSAGE_UNHANDLED(handled = false)
886 IPC_END_MESSAGE_MAP()
887 return handled;
[email protected]103607e2010-02-01 18:57:09888}
889
[email protected]463ea5f2011-12-03 06:57:47890void NaClProcessHost::OnProcessCrashed(int exit_code) {
891 std::string message = base::StringPrintf(
892 "NaCl process exited with status %i (0x%x)", exit_code, exit_code);
893 LOG(ERROR) << message;
[email protected]103607e2010-02-01 18:57:09894}
895
[email protected]773ebb92011-11-15 19:06:52896void NaClProcessHost::OnProcessLaunched() {
[email protected]09afc2e2012-04-10 17:29:03897 if (!StartWithLaunchedProcess())
898 delete this;
[email protected]773ebb92011-11-15 19:06:52899}
900
901// The asynchronous attempt to get the IRT file open has completed.
902void NaClProcessHost::IrtReady() {
903 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
[email protected]09afc2e2012-04-10 17:29:03904 if (!nacl_browser->IrtAvailable() || !SendStart()) {
905 DLOG(ERROR) << "Cannot launch NaCl process";
[email protected]338466a82011-05-03 04:27:43906 delete this;
907 }
908}
909
[email protected]00d99542012-04-17 22:48:02910bool NaClProcessHost::ReplyToRenderer() {
[email protected]c47ec402010-07-29 10:20:49911 std::vector<nacl::FileDescriptor> handles_for_renderer;
[email protected]1d8a3d1f2011-02-19 07:11:52912 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) {
[email protected]c47ec402010-07-29 10:20:49913#if defined(OS_WIN)
914 // Copy the handle into the renderer process.
915 HANDLE handle_in_renderer;
[email protected]909c2402011-05-09 11:39:04916 if (!DuplicateHandle(base::GetCurrentProcessHandle(),
917 reinterpret_cast<HANDLE>(
918 internal_->sockets_for_renderer[i]),
919 chrome_render_message_filter_->peer_handle(),
920 &handle_in_renderer,
921 0, // Unused given DUPLICATE_SAME_ACCESS.
922 FALSE,
923 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
[email protected]09afc2e2012-04-10 17:29:03924 DLOG(ERROR) << "DuplicateHandle() failed";
925 return false;
[email protected]909c2402011-05-09 11:39:04926 }
[email protected]c47ec402010-07-29 10:20:49927 handles_for_renderer.push_back(
928 reinterpret_cast<nacl::FileDescriptor>(handle_in_renderer));
929#else
930 // No need to dup the imc_handle - we don't pass it anywhere else so
931 // it cannot be closed.
932 nacl::FileDescriptor imc_handle;
[email protected]1d8a3d1f2011-02-19 07:11:52933 imc_handle.fd = internal_->sockets_for_renderer[i];
[email protected]c47ec402010-07-29 10:20:49934 imc_handle.auto_close = true;
935 handles_for_renderer.push_back(imc_handle);
936#endif
937 }
938
939#if defined(OS_WIN)
[email protected]e4f6eb0232012-04-17 00:47:50940 // If we are on 64-bit Windows, the NaCl process's sandbox is
941 // managed by a different process from the renderer's sandbox. We
942 // need to inform the renderer's sandbox about the NaCl process so
943 // that the renderer can send handles to the NaCl process using
944 // BrokerDuplicateHandle().
945 if (RunningOnWOW64()) {
[email protected]171fa98d2012-04-23 21:34:01946 if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
[email protected]e4f6eb0232012-04-17 00:47:50947 DLOG(ERROR) << "Failed to add NaCl process PID";
948 return false;
949 }
950 }
[email protected]fb1277e82009-11-21 20:32:30951#endif
952
[email protected]2ccf45c2011-08-19 23:35:50953 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams(
[email protected]171fa98d2012-04-23 21:34:01954 reply_msg_, handles_for_renderer);
[email protected]92d56412011-03-24 20:53:52955 chrome_render_message_filter_->Send(reply_msg_);
956 chrome_render_message_filter_ = NULL;
[email protected]fb1277e82009-11-21 20:32:30957 reply_msg_ = NULL;
[email protected]1d8a3d1f2011-02-19 07:11:52958 internal_->sockets_for_renderer.clear();
[email protected]00d99542012-04-17 22:48:02959 return true;
960}
[email protected]fb1277e82009-11-21 20:32:30961
[email protected]00d99542012-04-17 22:48:02962bool NaClProcessHost::StartNaClExecution() {
963 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
964
965 nacl::NaClStartParams params;
966 params.validation_cache_key = nacl_browser->GetValidatorCacheKey();
967 params.version = chrome::VersionInfo().CreateVersionString();
968 params.enable_exception_handling = enable_exception_handling_;
969
970 base::PlatformFile irt_file = nacl_browser->IrtFile();
971 CHECK_NE(irt_file, base::kInvalidPlatformFileValue);
972
973 const ChildProcessData& data = process_->GetData();
[email protected]1d8a3d1f2011-02-19 07:11:52974 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) {
[email protected]00d99542012-04-17 22:48:02975 if (!ShareHandleToSelLdr(data.handle,
976 internal_->sockets_for_sel_ldr[i], true,
977 &params.handles)) {
[email protected]09afc2e2012-04-10 17:29:03978 return false;
[email protected]c47ec402010-07-29 10:20:49979 }
[email protected]773ebb92011-11-15 19:06:52980 }
981
982 // Send over the IRT file handle. We don't close our own copy!
[email protected]00d99542012-04-17 22:48:02983 if (!ShareHandleToSelLdr(data.handle, irt_file, false, &params.handles))
[email protected]09afc2e2012-04-10 17:29:03984 return false;
[email protected]c47ec402010-07-29 10:20:49985
[email protected]ab88d1542011-11-18 22:52:00986#if defined(OS_MACOSX)
987 // For dynamic loading support, NaCl requires a file descriptor that
988 // was created in /tmp, since those created with shm_open() are not
989 // mappable with PROT_EXEC. Rather than requiring an extra IPC
990 // round trip out of the sandbox, we create an FD here.
[email protected]cbbe7842011-11-17 22:01:25991 base::SharedMemory memory_buffer;
[email protected]b05df6b2011-12-01 23:19:31992 base::SharedMemoryCreateOptions options;
993 options.size = 1;
994 options.executable = true;
995 if (!memory_buffer.Create(options)) {
[email protected]09afc2e2012-04-10 17:29:03996 DLOG(ERROR) << "Failed to allocate memory buffer";
997 return false;
[email protected]2c68bf032010-11-11 23:16:30998 }
[email protected]cbbe7842011-11-17 22:01:25999 nacl::FileDescriptor memory_fd;
1000 memory_fd.fd = dup(memory_buffer.handle().fd);
1001 if (memory_fd.fd < 0) {
[email protected]09afc2e2012-04-10 17:29:031002 DLOG(ERROR) << "Failed to dup() a file descriptor";
1003 return false;
[email protected]cbbe7842011-11-17 22:01:251004 }
1005 memory_fd.auto_close = true;
[email protected]00d99542012-04-17 22:48:021006 params.handles.push_back(memory_fd);
[email protected]2c68bf032010-11-11 23:16:301007#endif
1008
[email protected]00d99542012-04-17 22:48:021009 IPC::Message* start_message = new NaClProcessMsg_Start(params);
[email protected]b39c6d92012-01-31 16:38:411010#if defined(OS_WIN)
[email protected]5ca93be2012-03-21 20:04:061011 if (debug_context_ != NULL) {
1012 debug_context_->SetStartMessage(start_message);
[email protected]b39c6d92012-01-31 16:38:411013 debug_context_->SendStartMessage();
1014 } else {
[email protected]5ca93be2012-03-21 20:04:061015 process_->Send(start_message);
[email protected]b39c6d92012-01-31 16:38:411016 }
1017#else
[email protected]5ca93be2012-03-21 20:04:061018 process_->Send(start_message);
[email protected]b39c6d92012-01-31 16:38:411019#endif
1020
[email protected]1d8a3d1f2011-02-19 07:11:521021 internal_->sockets_for_sel_ldr.clear();
[email protected]09afc2e2012-04-10 17:29:031022 return true;
1023}
1024
[email protected]00d99542012-04-17 22:48:021025bool NaClProcessHost::SendStart() {
1026 return ReplyToRenderer() && StartNaClExecution();
1027}
1028
[email protected]09afc2e2012-04-10 17:29:031029bool NaClProcessHost::StartWithLaunchedProcess() {
1030#if defined(OS_LINUX)
1031 if (wait_for_nacl_gdb_) {
1032 if (LaunchNaClGdb(base::GetProcId(process_->GetData().handle))) {
1033 // We will be called with wait_for_nacl_gdb_ = false once debugger is
1034 // attached to the program.
1035 return true;
1036 }
1037 DLOG(ERROR) << "Failed to launch debugger";
1038 // Continue execution without debugger.
1039 }
1040#endif
1041
1042 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
1043 if (nacl_browser->IrtAvailable())
1044 return SendStart(); // The IRT is already open. Away we go.
1045
1046 // We're waiting for the IRT to be open.
1047 return nacl_browser->MakeIrtAvailable(
1048 base::Bind(&NaClProcessHost::IrtReady, weak_factory_.GetWeakPtr()));
[email protected]d032f492009-09-29 00:33:461049}
1050
[email protected]4a0141b2012-03-27 01:15:301051void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
1052 bool* result) {
1053 *result = NaClBrowser::GetInstance()->QueryKnownToValidate(signature);
1054}
1055
1056void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
1057 NaClBrowser::GetInstance()->SetKnownToValidate(signature);
1058}