Home | History | Annotate | Download | only in browser
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "components/nacl/browser/nacl_process_host.h"
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/base_switches.h"
     12 #include "base/bind.h"
     13 #include "base/command_line.h"
     14 #include "base/file_util.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/metrics/histogram.h"
     17 #include "base/path_service.h"
     18 #include "base/process/launch.h"
     19 #include "base/process/process_iterator.h"
     20 #include "base/rand_util.h"
     21 #include "base/strings/string_number_conversions.h"
     22 #include "base/strings/string_split.h"
     23 #include "base/strings/string_util.h"
     24 #include "base/strings/stringprintf.h"
     25 #include "base/strings/utf_string_conversions.h"
     26 #include "base/threading/sequenced_worker_pool.h"
     27 #include "base/win/windows_version.h"
     28 #include "build/build_config.h"
     29 #include "components/nacl/browser/nacl_browser.h"
     30 #include "components/nacl/browser/nacl_browser_delegate.h"
     31 #include "components/nacl/browser/nacl_host_message_filter.h"
     32 #include "components/nacl/common/nacl_cmd_line.h"
     33 #include "components/nacl/common/nacl_host_messages.h"
     34 #include "components/nacl/common/nacl_messages.h"
     35 #include "components/nacl/common/nacl_process_type.h"
     36 #include "components/nacl/common/nacl_switches.h"
     37 #include "content/public/browser/browser_child_process_host.h"
     38 #include "content/public/browser/browser_ppapi_host.h"
     39 #include "content/public/browser/child_process_data.h"
     40 #include "content/public/browser/plugin_service.h"
     41 #include "content/public/browser/render_process_host.h"
     42 #include "content/public/browser/web_contents.h"
     43 #include "content/public/common/child_process_host.h"
     44 #include "content/public/common/content_switches.h"
     45 #include "content/public/common/process_type.h"
     46 #include "content/public/common/sandboxed_process_launcher_delegate.h"
     47 #include "ipc/ipc_channel.h"
     48 #include "ipc/ipc_switches.h"
     49 #include "native_client/src/shared/imc/nacl_imc_c.h"
     50 #include "net/base/net_util.h"
     51 #include "net/socket/tcp_listen_socket.h"
     52 #include "ppapi/host/host_factory.h"
     53 #include "ppapi/host/ppapi_host.h"
     54 #include "ppapi/proxy/ppapi_messages.h"
     55 #include "ppapi/shared_impl/ppapi_constants.h"
     56 #include "ppapi/shared_impl/ppapi_nacl_plugin_args.h"
     57 
     58 #if defined(OS_POSIX)
     59 
     60 #include <fcntl.h>
     61 
     62 #include "ipc/ipc_channel_posix.h"
     63 #elif defined(OS_WIN)
     64 #include <windows.h>
     65 
     66 #include "base/threading/thread.h"
     67 #include "base/win/scoped_handle.h"
     68 #include "components/nacl/browser/nacl_broker_service_win.h"
     69 #include "components/nacl/common/nacl_debug_exception_handler_win.h"
     70 #include "content/public/common/sandbox_init.h"
     71 #endif
     72 
     73 using content::BrowserThread;
     74 using content::ChildProcessData;
     75 using content::ChildProcessHost;
     76 using ppapi::proxy::SerializedHandle;
     77 
     78 #if defined(OS_WIN)
     79 
     80 namespace {
     81 
     82 // Looks for the largest contiguous unallocated region of address
     83 // space and returns it via |*out_addr| and |*out_size|.
     84 void FindAddressSpace(base::ProcessHandle process,
     85                       char** out_addr, size_t* out_size) {
     86   *out_addr = NULL;
     87   *out_size = 0;
     88   char* addr = 0;
     89   while (true) {
     90     MEMORY_BASIC_INFORMATION info;
     91     size_t result = VirtualQueryEx(process, static_cast<void*>(addr),
     92                                    &info, sizeof(info));
     93     if (result < sizeof(info))
     94       break;
     95     if (info.State == MEM_FREE && info.RegionSize > *out_size) {
     96       *out_addr = addr;
     97       *out_size = info.RegionSize;
     98     }
     99     addr += info.RegionSize;
    100   }
    101 }
    102 
    103 #ifdef _DLL
    104 
    105 bool IsInPath(const std::string& path_env_var, const std::string& dir) {
    106   std::vector<std::string> split;
    107   base::SplitString(path_env_var, ';', &split);
    108   for (std::vector<std::string>::const_iterator i(split.begin());
    109        i != split.end();
    110        ++i) {
    111     if (*i == dir)
    112       return true;
    113   }
    114   return false;
    115 }
    116 
    117 #endif  // _DLL
    118 
    119 }  // namespace
    120 
    121 namespace nacl {
    122 
    123 // Allocates |size| bytes of address space in the given process at a
    124 // randomised address.
    125 void* AllocateAddressSpaceASLR(base::ProcessHandle process, size_t size) {
    126   char* addr;
    127   size_t avail_size;
    128   FindAddressSpace(process, &addr, &avail_size);
    129   if (avail_size < size)
    130     return NULL;
    131   size_t offset = base::RandGenerator(avail_size - size);
    132   const int kPageSize = 0x10000;
    133   void* request_addr =
    134       reinterpret_cast<void*>(reinterpret_cast<uint64>(addr + offset)
    135                               & ~(kPageSize - 1));
    136   return VirtualAllocEx(process, request_addr, size,
    137                         MEM_RESERVE, PAGE_NOACCESS);
    138 }
    139 
    140 }  // namespace nacl
    141 
    142 #endif  // defined(OS_WIN)
    143 
    144 namespace {
    145 
    146 #if defined(OS_WIN)
    147 bool RunningOnWOW64() {
    148   return (base::win::OSInfo::GetInstance()->wow64_status() ==
    149           base::win::OSInfo::WOW64_ENABLED);
    150 }
    151 #endif
    152 
    153 // NOTE: changes to this class need to be reviewed by the security team.
    154 class NaClSandboxedProcessLauncherDelegate
    155     : public content::SandboxedProcessLauncherDelegate {
    156  public:
    157   NaClSandboxedProcessLauncherDelegate(ChildProcessHost* host)
    158 #if defined(OS_POSIX)
    159       : ipc_fd_(host->TakeClientFileDescriptor())
    160 #endif
    161   {}
    162 
    163   virtual ~NaClSandboxedProcessLauncherDelegate() {}
    164 
    165 #if defined(OS_WIN)
    166   virtual void PostSpawnTarget(base::ProcessHandle process) {
    167     // For Native Client sel_ldr processes on 32-bit Windows, reserve 1 GB of
    168     // address space to prevent later failure due to address space fragmentation
    169     // from .dll loading. The NaCl process will attempt to locate this space by
    170     // scanning the address space using VirtualQuery.
    171     // TODO(bbudge) Handle the --no-sandbox case.
    172     // http://code.google.com/p/nativeclient/issues/detail?id=2131
    173     const SIZE_T kNaClSandboxSize = 1 << 30;
    174     if (!nacl::AllocateAddressSpaceASLR(process, kNaClSandboxSize)) {
    175       DLOG(WARNING) << "Failed to reserve address space for Native Client";
    176     }
    177   }
    178 #elif defined(OS_POSIX)
    179   virtual bool ShouldUseZygote() OVERRIDE {
    180     return true;
    181   }
    182   virtual int GetIpcFd() OVERRIDE {
    183     return ipc_fd_;
    184   }
    185 #endif  // OS_WIN
    186 
    187  private:
    188 #if defined(OS_POSIX)
    189   int ipc_fd_;
    190 #endif  // OS_POSIX
    191 };
    192 
    193 void SetCloseOnExec(NaClHandle fd) {
    194 #if defined(OS_POSIX)
    195   int flags = fcntl(fd, F_GETFD);
    196   CHECK_NE(flags, -1);
    197   int rc = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
    198   CHECK_EQ(rc, 0);
    199 #endif
    200 }
    201 
    202 bool ShareHandleToSelLdr(
    203     base::ProcessHandle processh,
    204     NaClHandle sourceh,
    205     bool close_source,
    206     std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) {
    207 #if defined(OS_WIN)
    208   HANDLE channel;
    209   int flags = DUPLICATE_SAME_ACCESS;
    210   if (close_source)
    211     flags |= DUPLICATE_CLOSE_SOURCE;
    212   if (!DuplicateHandle(GetCurrentProcess(),
    213                        reinterpret_cast<HANDLE>(sourceh),
    214                        processh,
    215                        &channel,
    216                        0,  // Unused given DUPLICATE_SAME_ACCESS.
    217                        FALSE,
    218                        flags)) {
    219     LOG(ERROR) << "DuplicateHandle() failed";
    220     return false;
    221   }
    222   handles_for_sel_ldr->push_back(
    223       reinterpret_cast<nacl::FileDescriptor>(channel));
    224 #else
    225   nacl::FileDescriptor channel;
    226   channel.fd = sourceh;
    227   channel.auto_close = close_source;
    228   handles_for_sel_ldr->push_back(channel);
    229 #endif
    230   return true;
    231 }
    232 
    233 }  // namespace
    234 
    235 namespace nacl {
    236 
    237 struct NaClProcessHost::NaClInternal {
    238   NaClHandle socket_for_renderer;
    239   NaClHandle socket_for_sel_ldr;
    240 
    241   NaClInternal()
    242     : socket_for_renderer(NACL_INVALID_HANDLE),
    243       socket_for_sel_ldr(NACL_INVALID_HANDLE) { }
    244 };
    245 
    246 // -----------------------------------------------------------------------------
    247 
    248 unsigned NaClProcessHost::keepalive_throttle_interval_milliseconds_ =
    249     ppapi::kKeepaliveThrottleIntervalDefaultMilliseconds;
    250 
    251 NaClProcessHost::NaClProcessHost(const GURL& manifest_url,
    252                                  ppapi::PpapiPermissions permissions,
    253                                  int render_view_id,
    254                                  uint32 permission_bits,
    255                                  bool uses_irt,
    256                                  bool uses_nonsfi_mode,
    257                                  bool enable_dyncode_syscalls,
    258                                  bool enable_exception_handling,
    259                                  bool enable_crash_throttling,
    260                                  bool off_the_record,
    261                                  const base::FilePath& profile_directory)
    262     : manifest_url_(manifest_url),
    263       permissions_(permissions),
    264 #if defined(OS_WIN)
    265       process_launched_by_broker_(false),
    266 #endif
    267       reply_msg_(NULL),
    268 #if defined(OS_WIN)
    269       debug_exception_handler_requested_(false),
    270 #endif
    271       internal_(new NaClInternal()),
    272       weak_factory_(this),
    273       uses_irt_(uses_irt),
    274       uses_nonsfi_mode_(uses_nonsfi_mode),
    275       enable_debug_stub_(false),
    276       enable_dyncode_syscalls_(enable_dyncode_syscalls),
    277       enable_exception_handling_(enable_exception_handling),
    278       enable_crash_throttling_(enable_crash_throttling),
    279       off_the_record_(off_the_record),
    280       profile_directory_(profile_directory),
    281       render_view_id_(render_view_id) {
    282   process_.reset(content::BrowserChildProcessHost::Create(
    283       PROCESS_TYPE_NACL_LOADER, this));
    284 
    285   // Set the display name so the user knows what plugin the process is running.
    286   // We aren't on the UI thread so getting the pref locale for language
    287   // formatting isn't possible, so IDN will be lost, but this is probably OK
    288   // for this use case.
    289   process_->SetName(net::FormatUrl(manifest_url_, std::string()));
    290 
    291   enable_debug_stub_ = CommandLine::ForCurrentProcess()->HasSwitch(
    292       switches::kEnableNaClDebug);
    293 }
    294 
    295 NaClProcessHost::~NaClProcessHost() {
    296   // Report exit status only if the process was successfully started.
    297   if (process_->GetData().handle != base::kNullProcessHandle) {
    298     int exit_code = 0;
    299     process_->GetTerminationStatus(false /* known_dead */, &exit_code);
    300     std::string message =
    301         base::StringPrintf("NaCl process exited with status %i (0x%x)",
    302                            exit_code, exit_code);
    303     if (exit_code == 0) {
    304       VLOG(1) << message;
    305     } else {
    306       LOG(ERROR) << message;
    307     }
    308     NaClBrowser::GetInstance()->OnProcessEnd(process_->GetData().id);
    309   }
    310 
    311   if (internal_->socket_for_renderer != NACL_INVALID_HANDLE) {
    312     if (NaClClose(internal_->socket_for_renderer) != 0) {
    313       NOTREACHED() << "NaClClose() failed";
    314     }
    315   }
    316 
    317   if (internal_->socket_for_sel_ldr != NACL_INVALID_HANDLE) {
    318     if (NaClClose(internal_->socket_for_sel_ldr) != 0) {
    319       NOTREACHED() << "NaClClose() failed";
    320     }
    321   }
    322 
    323   if (reply_msg_) {
    324     // The process failed to launch for some reason.
    325     // Don't keep the renderer hanging.
    326     reply_msg_->set_reply_error();
    327     nacl_host_message_filter_->Send(reply_msg_);
    328   }
    329 #if defined(OS_WIN)
    330   if (process_launched_by_broker_) {
    331     NaClBrokerService::GetInstance()->OnLoaderDied();
    332   }
    333 #endif
    334 }
    335 
    336 void NaClProcessHost::OnProcessCrashed(int exit_status) {
    337   if (enable_crash_throttling_ &&
    338       !CommandLine::ForCurrentProcess()->HasSwitch(
    339           switches::kDisablePnaclCrashThrottling)) {
    340     NaClBrowser::GetInstance()->OnProcessCrashed();
    341   }
    342 }
    343 
    344 // This is called at browser startup.
    345 // static
    346 void NaClProcessHost::EarlyStartup() {
    347   NaClBrowser::GetInstance()->EarlyStartup();
    348   // Inform NaClBrowser that we exist and will have a debug port at some point.
    349 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
    350   // Open the IRT file early to make sure that it isn't replaced out from
    351   // under us by autoupdate.
    352   NaClBrowser::GetInstance()->EnsureIrtAvailable();
    353 #endif
    354   CommandLine* cmd = CommandLine::ForCurrentProcess();
    355   UMA_HISTOGRAM_BOOLEAN(
    356       "NaCl.nacl-gdb",
    357       !cmd->GetSwitchValuePath(switches::kNaClGdb).empty());
    358   UMA_HISTOGRAM_BOOLEAN(
    359       "NaCl.nacl-gdb-script",
    360       !cmd->GetSwitchValuePath(switches::kNaClGdbScript).empty());
    361   UMA_HISTOGRAM_BOOLEAN(
    362       "NaCl.enable-nacl-debug",
    363       cmd->HasSwitch(switches::kEnableNaClDebug));
    364   std::string nacl_debug_mask =
    365       cmd->GetSwitchValueASCII(switches::kNaClDebugMask);
    366   // By default, exclude debugging SSH and the PNaCl translator.
    367   // about::flags only allows empty flags as the default, so replace
    368   // the empty setting with the default. To debug all apps, use a wild-card.
    369   if (nacl_debug_mask.empty()) {
    370     nacl_debug_mask = "!*://*/*ssh_client.nmf,chrome://pnacl-translator/*";
    371   }
    372   NaClBrowser::GetDelegate()->SetDebugPatterns(nacl_debug_mask);
    373 }
    374 
    375 // static
    376 void NaClProcessHost::SetPpapiKeepAliveThrottleForTesting(
    377     unsigned milliseconds) {
    378   keepalive_throttle_interval_milliseconds_ = milliseconds;
    379 }
    380 
    381 void NaClProcessHost::Launch(
    382     NaClHostMessageFilter* nacl_host_message_filter,
    383     IPC::Message* reply_msg,
    384     const base::FilePath& manifest_path) {
    385   nacl_host_message_filter_ = nacl_host_message_filter;
    386   reply_msg_ = reply_msg;
    387   manifest_path_ = manifest_path;
    388 
    389   // Do not launch the requested NaCl module if NaCl is marked "unstable" due
    390   // to too many crashes within a given time period.
    391   if (enable_crash_throttling_ &&
    392       !CommandLine::ForCurrentProcess()->HasSwitch(
    393           switches::kDisablePnaclCrashThrottling) &&
    394       NaClBrowser::GetInstance()->IsThrottled()) {
    395     SendErrorToRenderer("Process creation was throttled due to excessive"
    396                         " crashes");
    397     delete this;
    398     return;
    399   }
    400 
    401   const CommandLine* cmd = CommandLine::ForCurrentProcess();
    402 #if defined(OS_WIN)
    403   if (cmd->HasSwitch(switches::kEnableNaClDebug) &&
    404       !cmd->HasSwitch(switches::kNoSandbox)) {
    405     // We don't switch off sandbox automatically for security reasons.
    406     SendErrorToRenderer("NaCl's GDB debug stub requires --no-sandbox flag"
    407                         " on Windows. See crbug.com/265624.");
    408     delete this;
    409     return;
    410   }
    411 #endif
    412   if (cmd->HasSwitch(switches::kNaClGdb) &&
    413       !cmd->HasSwitch(switches::kEnableNaClDebug)) {
    414     LOG(WARNING) << "--nacl-gdb flag requires --enable-nacl-debug flag";
    415   }
    416 
    417   // Start getting the IRT open asynchronously while we launch the NaCl process.
    418   // We'll make sure this actually finished in StartWithLaunchedProcess, below.
    419   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    420   nacl_browser->EnsureAllResourcesAvailable();
    421   if (!nacl_browser->IsOk()) {
    422     SendErrorToRenderer("could not find all the resources needed"
    423                         " to launch the process");
    424     delete this;
    425     return;
    426   }
    427 
    428   if (uses_nonsfi_mode_) {
    429     bool nonsfi_mode_forced_by_command_line = false;
    430     bool nonsfi_mode_allowed = false;
    431 #if defined(OS_LINUX)
    432     nonsfi_mode_forced_by_command_line =
    433         cmd->HasSwitch(switches::kEnableNaClNonSfiMode);
    434 #if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
    435     nonsfi_mode_allowed = NaClBrowser::GetDelegate()->IsNonSfiModeAllowed(
    436         nacl_host_message_filter->profile_directory(), manifest_url_);
    437 #endif
    438 #endif
    439     bool nonsfi_mode_enabled =
    440         nonsfi_mode_forced_by_command_line || nonsfi_mode_allowed;
    441 
    442     if (!nonsfi_mode_enabled) {
    443       SendErrorToRenderer(
    444           "NaCl non-SFI mode is not available for this platform"
    445           " and NaCl module.");
    446       delete this;
    447       return;
    448     }
    449   }
    450 
    451   // Rather than creating a socket pair in the renderer, and passing
    452   // one side through the browser to sel_ldr, socket pairs are created
    453   // in the browser and then passed to the renderer and sel_ldr.
    454   //
    455   // This is mainly for the benefit of Windows, where sockets cannot
    456   // be passed in messages, but are copied via DuplicateHandle().
    457   // This means the sandboxed renderer cannot send handles to the
    458   // browser process.
    459 
    460   NaClHandle pair[2];
    461   // Create a connected socket
    462   if (NaClSocketPair(pair) == -1) {
    463     SendErrorToRenderer("NaClSocketPair() failed");
    464     delete this;
    465     return;
    466   }
    467   internal_->socket_for_renderer = pair[0];
    468   internal_->socket_for_sel_ldr = pair[1];
    469   SetCloseOnExec(pair[0]);
    470   SetCloseOnExec(pair[1]);
    471 
    472   // Launch the process
    473   if (!LaunchSelLdr()) {
    474     delete this;
    475   }
    476 }
    477 
    478 void NaClProcessHost::OnChannelConnected(int32 peer_pid) {
    479   if (!CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    480           switches::kNaClGdb).empty()) {
    481     LaunchNaClGdb();
    482   }
    483 }
    484 
    485 #if defined(OS_WIN)
    486 void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
    487   process_launched_by_broker_ = true;
    488   process_->SetHandle(handle);
    489   SetDebugStubPort(nacl::kGdbDebugStubPortUnknown);
    490   if (!StartWithLaunchedProcess())
    491     delete this;
    492 }
    493 
    494 void NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker(bool success) {
    495   IPC::Message* reply = attach_debug_exception_handler_reply_msg_.release();
    496   NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply, success);
    497   Send(reply);
    498 }
    499 #endif
    500 
    501 // Needed to handle sync messages in OnMessageReceived.
    502 bool NaClProcessHost::Send(IPC::Message* msg) {
    503   return process_->Send(msg);
    504 }
    505 
    506 bool NaClProcessHost::LaunchNaClGdb() {
    507 #if defined(OS_WIN)
    508   base::FilePath nacl_gdb =
    509       CommandLine::ForCurrentProcess()->GetSwitchValuePath(switches::kNaClGdb);
    510   CommandLine cmd_line(nacl_gdb);
    511 #else
    512   CommandLine::StringType nacl_gdb =
    513       CommandLine::ForCurrentProcess()->GetSwitchValueNative(
    514           switches::kNaClGdb);
    515   CommandLine::StringVector argv;
    516   // We don't support spaces inside arguments in --nacl-gdb switch.
    517   base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
    518   CommandLine cmd_line(argv);
    519 #endif
    520   cmd_line.AppendArg("--eval-command");
    521   base::FilePath::StringType irt_path(
    522       NaClBrowser::GetInstance()->GetIrtFilePath().value());
    523   // Avoid back slashes because nacl-gdb uses posix escaping rules on Windows.
    524   // See issue https://code.google.com/p/nativeclient/issues/detail?id=3482.
    525   std::replace(irt_path.begin(), irt_path.end(), '\\', '/');
    526   cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt \"") + irt_path +
    527                            FILE_PATH_LITERAL("\""));
    528   if (!manifest_path_.empty()) {
    529     cmd_line.AppendArg("--eval-command");
    530     base::FilePath::StringType manifest_path_value(manifest_path_.value());
    531     std::replace(manifest_path_value.begin(), manifest_path_value.end(),
    532                  '\\', '/');
    533     cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest \"") +
    534                              manifest_path_value + FILE_PATH_LITERAL("\""));
    535   }
    536   cmd_line.AppendArg("--eval-command");
    537   cmd_line.AppendArg("target remote :4014");
    538   base::FilePath script = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
    539       switches::kNaClGdbScript);
    540   if (!script.empty()) {
    541     cmd_line.AppendArg("--command");
    542     cmd_line.AppendArgNative(script.value());
    543   }
    544   return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
    545 }
    546 
    547 bool NaClProcessHost::LaunchSelLdr() {
    548   std::string channel_id = process_->GetHost()->CreateChannel();
    549   if (channel_id.empty()) {
    550     SendErrorToRenderer("CreateChannel() failed");
    551     return false;
    552   }
    553 
    554   // Build command line for nacl.
    555 
    556 #if defined(OS_MACOSX)
    557   // The Native Client process needs to be able to allocate a 1GB contiguous
    558   // region to use as the client environment's virtual address space. ASLR
    559   // (PIE) interferes with this by making it possible that no gap large enough
    560   // to accomodate this request will exist in the child process' address
    561   // space. Disable PIE for NaCl processes. See http://crbug.com/90221 and
    562   // http://code.google.com/p/nativeclient/issues/detail?id=2043.
    563   int flags = ChildProcessHost::CHILD_NO_PIE;
    564 #elif defined(OS_LINUX)
    565   int flags = ChildProcessHost::CHILD_ALLOW_SELF;
    566 #else
    567   int flags = ChildProcessHost::CHILD_NORMAL;
    568 #endif
    569 
    570   base::FilePath exe_path = ChildProcessHost::GetChildPath(flags);
    571   if (exe_path.empty())
    572     return false;
    573 
    574 #if defined(OS_WIN)
    575   // On Windows 64-bit NaCl loader is called nacl64.exe instead of chrome.exe
    576   if (RunningOnWOW64()) {
    577     if (!NaClBrowser::GetInstance()->GetNaCl64ExePath(&exe_path)) {
    578       SendErrorToRenderer("could not get path to nacl64.exe");
    579       return false;
    580     }
    581 
    582 #ifdef _DLL
    583     // When using the DLL CRT on Windows, we need to amend the PATH to include
    584     // the location of the x64 CRT DLLs. This is only the case when using a
    585     // component=shared_library build (i.e. generally dev debug builds). The
    586     // x86 CRT DLLs are in e.g. out\Debug for chrome.exe etc., so the x64 ones
    587     // are put in out\Debug\x64 which we add to the PATH here so that loader
    588     // can find them. See http://crbug.com/346034.
    589     scoped_ptr<base::Environment> env(base::Environment::Create());
    590     static const char kPath[] = "PATH";
    591     std::string old_path;
    592     base::FilePath module_path;
    593     if (!PathService::Get(base::FILE_MODULE, &module_path)) {
    594       SendErrorToRenderer("could not get path to current module");
    595       return false;
    596     }
    597     std::string x64_crt_path =
    598         base::WideToUTF8(module_path.DirName().Append(L"x64").value());
    599     if (!env->GetVar(kPath, &old_path)) {
    600       env->SetVar(kPath, x64_crt_path);
    601     } else if (!IsInPath(old_path, x64_crt_path)) {
    602       std::string new_path(old_path);
    603       new_path.append(";");
    604       new_path.append(x64_crt_path);
    605       env->SetVar(kPath, new_path);
    606     }
    607 #endif  // _DLL
    608   }
    609 #endif
    610 
    611   scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
    612   CopyNaClCommandLineArguments(cmd_line.get());
    613 
    614   cmd_line->AppendSwitchASCII(switches::kProcessType,
    615                               (uses_nonsfi_mode_ ?
    616                                switches::kNaClLoaderNonSfiProcess :
    617                                switches::kNaClLoaderProcess));
    618   cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
    619   if (NaClBrowser::GetDelegate()->DialogsAreSuppressed())
    620     cmd_line->AppendSwitch(switches::kNoErrorDialogs);
    621 
    622   // On Windows we might need to start the broker process to launch a new loader
    623 #if defined(OS_WIN)
    624   if (RunningOnWOW64()) {
    625     if (!NaClBrokerService::GetInstance()->LaunchLoader(
    626             weak_factory_.GetWeakPtr(), channel_id)) {
    627       SendErrorToRenderer("broker service did not launch process");
    628       return false;
    629     }
    630     return true;
    631   }
    632 #endif
    633   process_->Launch(
    634       new NaClSandboxedProcessLauncherDelegate(process_->GetHost()),
    635       cmd_line.release());
    636   return true;
    637 }
    638 
    639 bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) {
    640   bool handled = true;
    641   if (uses_nonsfi_mode_) {
    642     // IPC messages relating to NaCl's validation cache must not be exposed
    643     // in Non-SFI Mode, otherwise a Non-SFI nexe could use
    644     // SetKnownToValidate to create a hole in the SFI sandbox.
    645     IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
    646       IPC_MESSAGE_HANDLER(NaClProcessHostMsg_PpapiChannelsCreated,
    647                           OnPpapiChannelsCreated)
    648       IPC_MESSAGE_UNHANDLED(handled = false)
    649     IPC_END_MESSAGE_MAP()
    650   } else {
    651     IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
    652       IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
    653                           OnQueryKnownToValidate)
    654       IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
    655                           OnSetKnownToValidate)
    656       IPC_MESSAGE_HANDLER_DELAY_REPLY(NaClProcessMsg_ResolveFileToken,
    657                                       OnResolveFileToken)
    658 #if defined(OS_WIN)
    659       IPC_MESSAGE_HANDLER_DELAY_REPLY(
    660           NaClProcessMsg_AttachDebugExceptionHandler,
    661           OnAttachDebugExceptionHandler)
    662       IPC_MESSAGE_HANDLER(NaClProcessHostMsg_DebugStubPortSelected,
    663                           OnDebugStubPortSelected)
    664 #endif
    665       IPC_MESSAGE_HANDLER(NaClProcessHostMsg_PpapiChannelsCreated,
    666                           OnPpapiChannelsCreated)
    667       IPC_MESSAGE_UNHANDLED(handled = false)
    668     IPC_END_MESSAGE_MAP()
    669   }
    670   return handled;
    671 }
    672 
    673 void NaClProcessHost::OnProcessLaunched() {
    674   if (!StartWithLaunchedProcess())
    675     delete this;
    676 }
    677 
    678 // Called when the NaClBrowser singleton has been fully initialized.
    679 void NaClProcessHost::OnResourcesReady() {
    680   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    681   if (!nacl_browser->IsReady()) {
    682     SendErrorToRenderer("could not acquire shared resources needed by NaCl");
    683     delete this;
    684   } else if (!StartNaClExecution()) {
    685     delete this;
    686   }
    687 }
    688 
    689 bool NaClProcessHost::ReplyToRenderer(
    690     const IPC::ChannelHandle& ppapi_channel_handle,
    691     const IPC::ChannelHandle& trusted_channel_handle,
    692     const IPC::ChannelHandle& manifest_service_channel_handle) {
    693 #if defined(OS_WIN)
    694   // If we are on 64-bit Windows, the NaCl process's sandbox is
    695   // managed by a different process from the renderer's sandbox.  We
    696   // need to inform the renderer's sandbox about the NaCl process so
    697   // that the renderer can send handles to the NaCl process using
    698   // BrokerDuplicateHandle().
    699   if (RunningOnWOW64()) {
    700     if (!content::BrokerAddTargetPeer(process_->GetData().handle)) {
    701       SendErrorToRenderer("BrokerAddTargetPeer() failed");
    702       return false;
    703     }
    704   }
    705 #endif
    706 
    707   FileDescriptor imc_handle_for_renderer;
    708 #if defined(OS_WIN)
    709   // Copy the handle into the renderer process.
    710   HANDLE handle_in_renderer;
    711   if (!DuplicateHandle(base::GetCurrentProcessHandle(),
    712                        reinterpret_cast<HANDLE>(
    713                            internal_->socket_for_renderer),
    714                        nacl_host_message_filter_->PeerHandle(),
    715                        &handle_in_renderer,
    716                        0,  // Unused given DUPLICATE_SAME_ACCESS.
    717                        FALSE,
    718                        DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    719     SendErrorToRenderer("DuplicateHandle() failed");
    720     return false;
    721   }
    722   imc_handle_for_renderer = reinterpret_cast<FileDescriptor>(
    723       handle_in_renderer);
    724 #else
    725   // No need to dup the imc_handle - we don't pass it anywhere else so
    726   // it cannot be closed.
    727   FileDescriptor imc_handle;
    728   imc_handle.fd = internal_->socket_for_renderer;
    729   imc_handle.auto_close = true;
    730   imc_handle_for_renderer = imc_handle;
    731 #endif
    732 
    733   const ChildProcessData& data = process_->GetData();
    734   SendMessageToRenderer(
    735       NaClLaunchResult(imc_handle_for_renderer,
    736                        ppapi_channel_handle,
    737                        trusted_channel_handle,
    738                        manifest_service_channel_handle,
    739                        base::GetProcId(data.handle),
    740                        data.id),
    741       std::string() /* error_message */);
    742   internal_->socket_for_renderer = NACL_INVALID_HANDLE;
    743   return true;
    744 }
    745 
    746 void NaClProcessHost::SendErrorToRenderer(const std::string& error_message) {
    747   LOG(ERROR) << "NaCl process launch failed: " << error_message;
    748   SendMessageToRenderer(NaClLaunchResult(), error_message);
    749 }
    750 
    751 void NaClProcessHost::SendMessageToRenderer(
    752     const NaClLaunchResult& result,
    753     const std::string& error_message) {
    754   DCHECK(nacl_host_message_filter_);
    755   DCHECK(reply_msg_);
    756   if (nacl_host_message_filter_ != NULL && reply_msg_ != NULL) {
    757     NaClHostMsg_LaunchNaCl::WriteReplyParams(
    758         reply_msg_, result, error_message);
    759     nacl_host_message_filter_->Send(reply_msg_);
    760     nacl_host_message_filter_ = NULL;
    761     reply_msg_ = NULL;
    762   }
    763 }
    764 
    765 void NaClProcessHost::SetDebugStubPort(int port) {
    766   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    767   nacl_browser->SetProcessGdbDebugStubPort(process_->GetData().id, port);
    768 }
    769 
    770 #if defined(OS_POSIX)
    771 // TCP port we chose for NaCl debug stub. It can be any other number.
    772 static const int kInitialDebugStubPort = 4014;
    773 
    774 net::SocketDescriptor NaClProcessHost::GetDebugStubSocketHandle() {
    775   net::SocketDescriptor s = net::kInvalidSocket;
    776   // We always try to allocate the default port first. If this fails, we then
    777   // allocate any available port.
    778   // On success, if the test system has register a handler
    779   // (GdbDebugStubPortListener), we fire a notification.
    780   int port = kInitialDebugStubPort;
    781   s = net::TCPListenSocket::CreateAndBind("127.0.0.1", port);
    782   if (s == net::kInvalidSocket) {
    783     s = net::TCPListenSocket::CreateAndBindAnyPort("127.0.0.1", &port);
    784   }
    785   if (s != net::kInvalidSocket) {
    786     SetDebugStubPort(port);
    787   }
    788   if (s == net::kInvalidSocket) {
    789     LOG(ERROR) << "failed to open socket for debug stub";
    790     return net::kInvalidSocket;
    791   } else {
    792     LOG(WARNING) << "debug stub on port " << port;
    793   }
    794   if (listen(s, 1)) {
    795     LOG(ERROR) << "listen() failed on debug stub socket";
    796     if (IGNORE_EINTR(close(s)) < 0)
    797       PLOG(ERROR) << "failed to close debug stub socket";
    798     return net::kInvalidSocket;
    799   }
    800   return s;
    801 }
    802 #endif
    803 
    804 #if defined(OS_WIN)
    805 void NaClProcessHost::OnDebugStubPortSelected(uint16_t debug_stub_port) {
    806   CHECK(!uses_nonsfi_mode_);
    807   SetDebugStubPort(debug_stub_port);
    808 }
    809 #endif
    810 
    811 bool NaClProcessHost::StartNaClExecution() {
    812   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    813 
    814   NaClStartParams params;
    815   // Enable PPAPI proxy channel creation only for renderer processes.
    816   params.enable_ipc_proxy = enable_ppapi_proxy();
    817   if (!uses_nonsfi_mode_) {
    818     params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
    819     params.validation_cache_key = nacl_browser->GetValidationCacheKey();
    820     params.version = NaClBrowser::GetDelegate()->GetVersionString();
    821     params.enable_exception_handling = enable_exception_handling_;
    822     params.enable_debug_stub = enable_debug_stub_ &&
    823         NaClBrowser::GetDelegate()->URLMatchesDebugPatterns(manifest_url_);
    824     params.uses_irt = uses_irt_;
    825     params.enable_dyncode_syscalls = enable_dyncode_syscalls_;
    826   }
    827 
    828   const ChildProcessData& data = process_->GetData();
    829   if (!ShareHandleToSelLdr(data.handle,
    830                            internal_->socket_for_sel_ldr, true,
    831                            &params.handles)) {
    832     return false;
    833   }
    834 
    835   if (params.uses_irt) {
    836     const base::File& irt_file = nacl_browser->IrtFile();
    837     CHECK(irt_file.IsValid());
    838     // Send over the IRT file handle.  We don't close our own copy!
    839     if (!ShareHandleToSelLdr(data.handle, irt_file.GetPlatformFile(), false,
    840                              &params.handles)) {
    841       return false;
    842     }
    843   }
    844 
    845 #if defined(OS_MACOSX)
    846   // For dynamic loading support, NaCl requires a file descriptor that
    847   // was created in /tmp, since those created with shm_open() are not
    848   // mappable with PROT_EXEC.  Rather than requiring an extra IPC
    849   // round trip out of the sandbox, we create an FD here.
    850   base::SharedMemory memory_buffer;
    851   base::SharedMemoryCreateOptions options;
    852   options.size = 1;
    853   options.executable = true;
    854   if (!memory_buffer.Create(options)) {
    855     DLOG(ERROR) << "Failed to allocate memory buffer";
    856     return false;
    857   }
    858   FileDescriptor memory_fd;
    859   memory_fd.fd = dup(memory_buffer.handle().fd);
    860   if (memory_fd.fd < 0) {
    861     DLOG(ERROR) << "Failed to dup() a file descriptor";
    862     return false;
    863   }
    864   memory_fd.auto_close = true;
    865   params.handles.push_back(memory_fd);
    866 #endif
    867 
    868 #if defined(OS_POSIX)
    869   if (params.enable_debug_stub) {
    870     net::SocketDescriptor server_bound_socket = GetDebugStubSocketHandle();
    871     if (server_bound_socket != net::kInvalidSocket) {
    872       params.debug_stub_server_bound_socket =
    873           FileDescriptor(server_bound_socket, true);
    874     }
    875   }
    876 #endif
    877 
    878   process_->Send(new NaClProcessMsg_Start(params));
    879 
    880   internal_->socket_for_sel_ldr = NACL_INVALID_HANDLE;
    881   return true;
    882 }
    883 
    884 // This method is called when NaClProcessHostMsg_PpapiChannelCreated is
    885 // received.
    886 void NaClProcessHost::OnPpapiChannelsCreated(
    887     const IPC::ChannelHandle& browser_channel_handle,
    888     const IPC::ChannelHandle& ppapi_renderer_channel_handle,
    889     const IPC::ChannelHandle& trusted_renderer_channel_handle,
    890     const IPC::ChannelHandle& manifest_service_channel_handle) {
    891   if (!enable_ppapi_proxy()) {
    892     ReplyToRenderer(IPC::ChannelHandle(),
    893                     trusted_renderer_channel_handle,
    894                     manifest_service_channel_handle);
    895     return;
    896   }
    897 
    898   if (!ipc_proxy_channel_.get()) {
    899     DCHECK_EQ(PROCESS_TYPE_NACL_LOADER, process_->GetData().process_type);
    900 
    901     ipc_proxy_channel_ =
    902         IPC::ChannelProxy::Create(browser_channel_handle,
    903                                   IPC::Channel::MODE_CLIENT,
    904                                   NULL,
    905                                   base::MessageLoopProxy::current().get());
    906     // Create the browser ppapi host and enable PPAPI message dispatching to the
    907     // browser process.
    908     ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
    909         ipc_proxy_channel_.get(),  // sender
    910         permissions_,
    911         process_->GetData().handle,
    912         ipc_proxy_channel_.get(),
    913         nacl_host_message_filter_->render_process_id(),
    914         render_view_id_,
    915         profile_directory_));
    916     ppapi_host_->SetOnKeepaliveCallback(
    917         NaClBrowser::GetDelegate()->GetOnKeepaliveCallback());
    918 
    919     ppapi::PpapiNaClPluginArgs args;
    920     args.off_the_record = nacl_host_message_filter_->off_the_record();
    921     args.permissions = permissions_;
    922     args.keepalive_throttle_interval_milliseconds =
    923         keepalive_throttle_interval_milliseconds_;
    924     CommandLine* cmdline = CommandLine::ForCurrentProcess();
    925     DCHECK(cmdline);
    926     std::string flag_whitelist[] = {
    927       switches::kV,
    928       switches::kVModule,
    929     };
    930     for (size_t i = 0; i < arraysize(flag_whitelist); ++i) {
    931       std::string value = cmdline->GetSwitchValueASCII(flag_whitelist[i]);
    932       if (!value.empty()) {
    933         args.switch_names.push_back(flag_whitelist[i]);
    934         args.switch_values.push_back(value);
    935       }
    936     }
    937 
    938     ppapi_host_->GetPpapiHost()->AddHostFactoryFilter(
    939         scoped_ptr<ppapi::host::HostFactory>(
    940             NaClBrowser::GetDelegate()->CreatePpapiHostFactory(
    941                 ppapi_host_.get())));
    942 
    943     // Send a message to initialize the IPC dispatchers in the NaCl plugin.
    944     ipc_proxy_channel_->Send(new PpapiMsg_InitializeNaClDispatcher(args));
    945 
    946     // Let the renderer know that the IPC channels are established.
    947     ReplyToRenderer(ppapi_renderer_channel_handle,
    948                     trusted_renderer_channel_handle,
    949                     manifest_service_channel_handle);
    950   } else {
    951     // Attempt to open more than 1 browser channel is not supported.
    952     // Shut down the NaCl process.
    953     process_->GetHost()->ForceShutdown();
    954   }
    955 }
    956 
    957 bool NaClProcessHost::StartWithLaunchedProcess() {
    958   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    959 
    960   if (nacl_browser->IsReady()) {
    961     return StartNaClExecution();
    962   } else if (nacl_browser->IsOk()) {
    963     nacl_browser->WaitForResources(
    964         base::Bind(&NaClProcessHost::OnResourcesReady,
    965                    weak_factory_.GetWeakPtr()));
    966     return true;
    967   } else {
    968     SendErrorToRenderer("previously failed to acquire shared resources");
    969     return false;
    970   }
    971 }
    972 
    973 void NaClProcessHost::OnQueryKnownToValidate(const std::string& signature,
    974                                              bool* result) {
    975   CHECK(!uses_nonsfi_mode_);
    976   NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
    977   *result = nacl_browser->QueryKnownToValidate(signature, off_the_record_);
    978 }
    979 
    980 void NaClProcessHost::OnSetKnownToValidate(const std::string& signature) {
    981   CHECK(!uses_nonsfi_mode_);
    982   NaClBrowser::GetInstance()->SetKnownToValidate(
    983       signature, off_the_record_);
    984 }
    985 
    986 void NaClProcessHost::FileResolved(
    987     const base::FilePath& file_path,
    988     IPC::Message* reply_msg,
    989     base::File file) {
    990   if (file.IsValid()) {
    991     IPC::PlatformFileForTransit handle = IPC::TakeFileHandleForProcess(
    992         file.Pass(),
    993         process_->GetData().handle);
    994     NaClProcessMsg_ResolveFileToken::WriteReplyParams(
    995         reply_msg,
    996         handle,
    997         file_path);
    998   } else {
    999     NaClProcessMsg_ResolveFileToken::WriteReplyParams(
   1000         reply_msg,
   1001         IPC::InvalidPlatformFileForTransit(),
   1002         base::FilePath());
   1003   }
   1004   Send(reply_msg);
   1005 }
   1006 
   1007 void NaClProcessHost::OnResolveFileToken(uint64 file_token_lo,
   1008                                          uint64 file_token_hi,
   1009                                          IPC::Message* reply_msg) {
   1010   // Was the file registered?
   1011   //
   1012   // Note that the file path cache is of bounded size, and old entries can get
   1013   // evicted.  If a large number of NaCl modules are being launched at once,
   1014   // resolving the file_token may fail because the path cache was thrashed
   1015   // while the file_token was in flight.  In this case the query fails, and we
   1016   // need to fall back to the slower path.
   1017   //
   1018   // However: each NaCl process will consume 2-3 entries as it starts up, this
   1019   // means that eviction will not happen unless you start up 33+ NaCl processes
   1020   // at the same time, and this still requires worst-case timing.  As a
   1021   // practical matter, no entries should be evicted prematurely.
   1022   // The cache itself should take ~ (150 characters * 2 bytes/char + ~60 bytes
   1023   // data structure overhead) * 100 = 35k when full, so making it bigger should
   1024   // not be a problem, if needed.
   1025   //
   1026   // Each NaCl process will consume 2-3 entries because the manifest and main
   1027   // nexe are currently not resolved.  Shared libraries will be resolved.  They
   1028   // will be loaded sequentially, so they will only consume a single entry
   1029   // while the load is in flight.
   1030   //
   1031   // TODO(ncbray): track behavior with UMA. If entries are getting evicted or
   1032   // bogus keys are getting queried, this would be good to know.
   1033   CHECK(!uses_nonsfi_mode_);
   1034   base::FilePath file_path;
   1035   if (!NaClBrowser::GetInstance()->GetFilePath(
   1036         file_token_lo, file_token_hi, &file_path)) {
   1037     NaClProcessMsg_ResolveFileToken::WriteReplyParams(
   1038         reply_msg,
   1039         IPC::InvalidPlatformFileForTransit(),
   1040         base::FilePath());
   1041     Send(reply_msg);
   1042     return;
   1043   }
   1044 
   1045   // Open the file.
   1046   if (!base::PostTaskAndReplyWithResult(
   1047           content::BrowserThread::GetBlockingPool(),
   1048           FROM_HERE,
   1049           base::Bind(OpenNaClExecutableImpl, file_path),
   1050           base::Bind(&NaClProcessHost::FileResolved,
   1051                      weak_factory_.GetWeakPtr(),
   1052                      file_path,
   1053                      reply_msg))) {
   1054      NaClProcessMsg_ResolveFileToken::WriteReplyParams(
   1055          reply_msg,
   1056          IPC::InvalidPlatformFileForTransit(),
   1057          base::FilePath());
   1058      Send(reply_msg);
   1059   }
   1060 }
   1061 
   1062 #if defined(OS_WIN)
   1063 void NaClProcessHost::OnAttachDebugExceptionHandler(const std::string& info,
   1064                                                     IPC::Message* reply_msg) {
   1065   CHECK(!uses_nonsfi_mode_);
   1066   if (!AttachDebugExceptionHandler(info, reply_msg)) {
   1067     // Send failure message.
   1068     NaClProcessMsg_AttachDebugExceptionHandler::WriteReplyParams(reply_msg,
   1069                                                                  false);
   1070     Send(reply_msg);
   1071   }
   1072 }
   1073 
   1074 bool NaClProcessHost::AttachDebugExceptionHandler(const std::string& info,
   1075                                                   IPC::Message* reply_msg) {
   1076   if (!enable_exception_handling_ && !enable_debug_stub_) {
   1077     DLOG(ERROR) <<
   1078         "Debug exception handler requested by NaCl process when not enabled";
   1079     return false;
   1080   }
   1081   if (debug_exception_handler_requested_) {
   1082     // The NaCl process should not request this multiple times.
   1083     DLOG(ERROR) << "Multiple AttachDebugExceptionHandler requests received";
   1084     return false;
   1085   }
   1086   debug_exception_handler_requested_ = true;
   1087 
   1088   base::ProcessId nacl_pid = base::GetProcId(process_->GetData().handle);
   1089   base::ProcessHandle temp_handle;
   1090   // We cannot use process_->GetData().handle because it does not have
   1091   // the necessary access rights.  We open the new handle here rather
   1092   // than in the NaCl broker process in case the NaCl loader process
   1093   // dies before the NaCl broker process receives the message we send.
   1094   // The debug exception handler uses DebugActiveProcess() to attach,
   1095   // but this takes a PID.  We need to prevent the NaCl loader's PID
   1096   // from being reused before DebugActiveProcess() is called, and
   1097   // holding a process handle open achieves this.
   1098   if (!base::OpenProcessHandleWithAccess(
   1099            nacl_pid,
   1100            base::kProcessAccessQueryInformation |
   1101            base::kProcessAccessSuspendResume |
   1102            base::kProcessAccessTerminate |
   1103            base::kProcessAccessVMOperation |
   1104            base::kProcessAccessVMRead |
   1105            base::kProcessAccessVMWrite |
   1106            base::kProcessAccessDuplicateHandle |
   1107            base::kProcessAccessWaitForTermination,
   1108            &temp_handle)) {
   1109     LOG(ERROR) << "Failed to get process handle";
   1110     return false;
   1111   }
   1112   base::win::ScopedHandle process_handle(temp_handle);
   1113 
   1114   attach_debug_exception_handler_reply_msg_.reset(reply_msg);
   1115   // If the NaCl loader is 64-bit, the process running its debug
   1116   // exception handler must be 64-bit too, so we use the 64-bit NaCl
   1117   // broker process for this.  Otherwise, on a 32-bit system, we use
   1118   // the 32-bit browser process to run the debug exception handler.
   1119   if (RunningOnWOW64()) {
   1120     return NaClBrokerService::GetInstance()->LaunchDebugExceptionHandler(
   1121                weak_factory_.GetWeakPtr(), nacl_pid, process_handle, info);
   1122   } else {
   1123     NaClStartDebugExceptionHandlerThread(
   1124         process_handle.Take(), info,
   1125         base::MessageLoopProxy::current(),
   1126         base::Bind(&NaClProcessHost::OnDebugExceptionHandlerLaunchedByBroker,
   1127                    weak_factory_.GetWeakPtr()));
   1128     return true;
   1129   }
   1130 }
   1131 #endif
   1132 
   1133 }  // namespace nacl
   1134