nacl_fork_delegate_linux.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "components/nacl/zygote/nacl_fork_delegate_linux.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <signal.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/resource.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/socket.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
16bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/cpu.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/files/scoped_file.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "base/memory/scoped_ptr.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/pickle.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/posix/global_descriptors.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/unix_domain_socket_linux.h"
263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/process/kill.h"
2758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/launch.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
29a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_paths.h"
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "components/nacl/common/nacl_switches.h"
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/loader/nacl_helper_linux.h"
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/common/content_descriptors.h"
33d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "content/public/common/content_switches.h"
340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "sandbox/linux/suid/client/setuid_sandbox_client.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
36ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace {
37ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Note these need to match up with their counterparts in nacl_helper_linux.c
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and nacl_helper_bootstrap_linux.c.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNaClHelperReservedAtZero[] =
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "--reserved_at_zero=0xXXXXXXXXXXXXXXXX";
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNaClHelperRDebug[] = "--r_debug=0xXXXXXXXXXXXXXXXX";
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#if defined(ARCH_CPU_X86)
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochbool NonZeroSegmentBaseIsSlow() {
46bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::CPU cpuid;
47bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Using a non-zero segment base is known to be very slow on Intel
48bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Atom CPUs.  See "Segmentation-based Memory Protection Mechanism
49bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // on Intel Atom Microarchitecture: Coding Optimizations" (Leonardo
50bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Potenza, Intel).
51bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //
52bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // The following list of CPU model numbers is taken from:
53bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // "Intel 64 and IA-32 Architectures Software Developer's Manual"
54bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // (http://download.intel.com/products/processor/manual/325462.pdf),
55bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // "Table 35-1. CPUID Signature Values of DisplayFamily_DisplayModel"
56bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // (Volume 3C, 35-1), which contains:
57bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //   "06_36H - Intel Atom S Processor Family
58bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //    06_1CH, 06_26H, 06_27H, 06_35, 06_36 - Intel Atom Processor Family"
59bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (cpuid.family() == 6) {
60bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    switch (cpuid.model()) {
61bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x1c:
62bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x26:
63bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x27:
64bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x35:
65bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x36:
66bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        return true;
67bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
68bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
69bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return false;
70bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
71bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#endif
72bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Send an IPC request on |ipc_channel|. The request is contained in
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |request_pickle| and can have file descriptors attached in |attached_fds|.
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |reply_data_buffer| must be allocated by the caller and will contain the
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// reply. The size of the reply will be written to |reply_size|.
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// This code assumes that only one thread can write to |ipc_channel| to make
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// requests.
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool SendIPCRequestAndReadReply(int ipc_channel,
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const std::vector<int>& attached_fds,
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const Pickle& request_pickle,
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                char* reply_data_buffer,
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                size_t reply_data_buffer_size,
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                ssize_t* reply_size) {
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK_LE(static_cast<size_t>(kNaClMaxIPCMessageLength),
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            reply_data_buffer_size);
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(reply_size);
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!UnixDomainSocket::SendMsg(ipc_channel, request_pickle.data(),
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 request_pickle.size(), attached_fds)) {
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "SendIPCRequestAndReadReply: SendMsg failed";
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Then read the remote reply.
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<int> received_fds;
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const ssize_t msg_len =
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UnixDomainSocket::RecvMsg(ipc_channel, reply_data_buffer,
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                reply_data_buffer_size, &received_fds);
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (msg_len <= 0) {
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "SendIPCRequestAndReadReply: RecvMsg failed";
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *reply_size = msg_len;
1053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
108d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace.
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochNaClForkDelegate::NaClForkDelegate()
111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    : status_(kNaClHelperUnused),
112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      fd_(-1) {}
113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid NaClForkDelegate::Init(const int sandboxdesc,
1150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                            const bool enable_layer1_sandbox) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::Init()";
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fds[2];
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1190529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client(
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      sandbox::SetuidSandboxClient::Create());
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // For communications between the NaCl loader process and
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the SUID sandbox.
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int nacl_sandbox_descriptor =
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Confirm a hard-wired assumption.
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(sandboxdesc, nacl_sandbox_descriptor);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FileHandleMappingVector fds_to_map;
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds_to_map.push_back(std::make_pair(fds[1], kNaClZygoteDescriptor));
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  fds_to_map.push_back(std::make_pair(sandboxdesc, nacl_sandbox_descriptor));
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Make sure that nacl_loader is started with a dummy file descriptor. This
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // is required because the setuid sandbox will always try to close a
1360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // hard-wired file descriptor.
1370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  base::ScopedFD dummy_fd(socket(PF_UNIX, SOCK_DGRAM, 0));
1380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  CHECK(dummy_fd.is_valid());
1390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  fds_to_map.push_back(std::make_pair(
1400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      dummy_fd.get(), setuid_sandbox_client->GetUniqueToChildFileDescriptor()));
1410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
142bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Using nacl_helper_bootstrap is not necessary on x86-64 because
143bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // NaCl's x86-64 sandbox is not zero-address-based.  Starting
144bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // nacl_helper through nacl_helper_bootstrap works on x86-64, but it
145bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // leaves nacl_helper_bootstrap mapped at a fixed address at the
146bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // bottom of the address space, which is undesirable because it
147bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // effectively defeats ASLR.
148bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#if defined(ARCH_CPU_X86_64)
149bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = false;
150bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#elif defined(ARCH_CPU_X86)
151bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Performance vs. security trade-off: We prefer using a
152bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // non-zero-address-based sandbox on x86-32 because it provides some
153bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // ASLR and so is more secure.  However, on Atom CPUs, using a
154bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // non-zero segment base is very slow, so we use a zero-based
155bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // sandbox on those.
156bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = NonZeroSegmentBaseIsSlow();
157bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#else
158bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = true;
159bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#endif
160bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status_ = kNaClHelperUnused;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath helper_exe;
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath helper_bootstrap_exe;
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!PathService::Get(nacl::FILE_NACL_HELPER, &helper_exe)) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperMissing;
166ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else if (kUseNaClBootstrap &&
167ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch             !PathService::Get(nacl::FILE_NACL_HELPER_BOOTSTRAP,
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &helper_bootstrap_exe)) {
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperBootstrapMissing;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (RunningOnValgrind()) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperValgrind;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    CommandLine::StringVector argv_to_launch;
174d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    {
175d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      CommandLine cmd_line(CommandLine::NO_PROGRAM);
176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (kUseNaClBootstrap)
177d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        cmd_line.SetProgram(helper_bootstrap_exe);
178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      else
179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        cmd_line.SetProgram(helper_exe);
180d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
181d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Append any switches that need to be forwarded to the NaCl helper.
182d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      static const char* kForwardSwitches[] = {
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switches::kDisableSeccompFilterSandbox,
184a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch        switches::kNaClDangerousNoSandboxNonSfi,
185d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switches::kNoSandbox,
186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      };
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      const CommandLine& current_cmd_line = *CommandLine::ForCurrentProcess();
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      cmd_line.CopySwitchesFrom(current_cmd_line, kForwardSwitches,
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                arraysize(kForwardSwitches));
190d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
191d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // The command line needs to be tightly controlled to use
192d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // |helper_bootstrap_exe|. So from now on, argv_to_launch should be
193d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // modified directly.
194d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      argv_to_launch = cmd_line.argv();
195d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
196ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kUseNaClBootstrap) {
197d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Arguments to the bootstrap helper which need to be at the start
198d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // of the command line, right after the helper's path.
199d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      CommandLine::StringVector bootstrap_prepend;
200d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(helper_exe.value());
201d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(kNaClHelperReservedAtZero);
202d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(kNaClHelperRDebug);
203d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      argv_to_launch.insert(argv_to_launch.begin() + 1,
204d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            bootstrap_prepend.begin(),
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            bootstrap_prepend.end());
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
2070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::LaunchOptions options;
2090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (enable_layer1_sandbox) {
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // NaCl needs to keep tight control of the cmd_line, so
2110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      // pass NULL and prepend the setuid sandbox wrapper manually.
2120529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      setuid_sandbox_client->PrependWrapper(NULL /* cmd_line */, &options);
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      base::FilePath sandbox_path =
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          setuid_sandbox_client->GetSandboxBinaryPath();
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      argv_to_launch.insert(argv_to_launch.begin(), sandbox_path.value());
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      setuid_sandbox_client->SetupLaunchEnvironment();
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.fds_to_remap = &fds_to_map;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The NaCl processes spawned may need to exceed the ambient soft limit
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on RLIMIT_AS to allocate the untrusted address space and its guard
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // regions.  The nacl_helper itself cannot just raise its own limit,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because the existing limit may prevent the initial exec of
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // nacl_helper_bootstrap from succeeding, with its large address space
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reservation.
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<int> max_these_limits;
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    max_these_limits.push_back(RLIMIT_AS);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.maximize_rlimits = &max_these_limits;
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
231d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!base::LaunchProcess(argv_to_launch, options, NULL))
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = kNaClHelperLaunchFailed;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // parent and error cases are handled below
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IGNORE_EINTR(close(fds[1])) != 0)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "close(fds[1]) failed";
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == kNaClHelperUnused) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ssize_t kExpectedLength = strlen(kNaClHelperStartupAck);
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char buf[kExpectedLength];
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait for ack from nacl_helper, indicating it is ready to help
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ssize_t nread = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (nread == kExpectedLength &&
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcmp(buf, kNaClHelperStartupAck, nread) == 0) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // all is well
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = kNaClHelperSuccess;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fd_ = fds[0];
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperAckFailed;
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Bad NaCl helper startup ack (" << nread << " bytes)";
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // becomes the default.
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fd_ = -1;
257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IGNORE_EINTR(close(fds[0])) != 0)
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "close(fds[0]) failed";
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClForkDelegate::InitialUMA(std::string* uma_name,
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int* uma_sample,
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int* uma_boundary_value) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_name = "NaCl.Client.Helper.InitState";
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_sample = status_;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_boundary_value = kNaClHelperStatusBoundary;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClForkDelegate::~NaClForkDelegate() {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // side effect of close: delegate process will terminate
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == kNaClHelperSuccess) {
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(fd_)) != 0)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "close(fd_) failed";
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClForkDelegate::CanHelp(const std::string& process_type,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               std::string* uma_name,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* uma_sample,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* uma_boundary_value) {
281e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (process_type != switches::kNaClLoaderProcess &&
282e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      process_type != switches::kNaClLoaderNonSfiProcess)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_name = "NaCl.Client.Helper.StateOnFork";
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_sample = status_;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_boundary_value = kNaClHelperStatusBoundary;
2871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
290e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochpid_t NaClForkDelegate::Fork(const std::string& process_type,
2910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             const std::vector<int>& fds,
2920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             const std::string& channel_id) {
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::Fork";
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(fds.size() == kNumPassedFDs);
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (status_ != kNaClHelperSuccess) {
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Cannot launch NaCl process: nacl_helper failed to start";
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return -1;
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // First, send a remote fork request.
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle write_pickle;
304f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  write_pickle.WriteInt(nacl::kNaClForkRequest);
305e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // TODO(hamaji): When we split the helper binary for non-SFI mode
306e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // from nacl_helper, stop sending this information.
307e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  const bool uses_nonsfi_mode =
308e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    process_type == switches::kNaClLoaderNonSfiProcess;
309e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  write_pickle.WriteBool(uses_nonsfi_mode);
3100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  write_pickle.WriteString(channel_id);
3113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char reply_buf[kNaClMaxIPCMessageLength];
3133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ssize_t reply_size = 0;
3143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool got_reply =
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      SendIPCRequestAndReadReply(fd_, fds, write_pickle,
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 reply_buf, sizeof(reply_buf), &reply_size);
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!got_reply) {
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Could not perform remote fork.";
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now see if the other end managed to fork.
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle reply_pickle(reply_buf, reply_size);
3243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PickleIterator iter(reply_pickle);
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pid_t nacl_child;
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&nacl_child)) {
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "NaClForkDelegate::Fork: pickle failed";
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(1) << "nacl_child is " << nacl_child;
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return nacl_child;
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool NaClForkDelegate::GetTerminationStatus(pid_t pid, bool known_dead,
3353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            base::TerminationStatus* status,
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            int* exit_code) {
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::GetTerminationStatus";
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(status);
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(exit_code);
3403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle write_pickle;
342f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  write_pickle.WriteInt(nacl::kNaClGetTerminationStatusRequest);
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  write_pickle.WriteInt(pid);
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  write_pickle.WriteBool(known_dead);
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const std::vector<int> empty_fds;
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char reply_buf[kNaClMaxIPCMessageLength];
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ssize_t reply_size = 0;
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool got_reply =
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      SendIPCRequestAndReadReply(fd_, empty_fds, write_pickle,
3513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 reply_buf, sizeof(reply_buf), &reply_size);
3523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!got_reply) {
3533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Could not perform remote GetTerminationStatus.";
3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle reply_pickle(reply_buf, reply_size);
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PickleIterator iter(reply_pickle);
3593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int termination_status;
3603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&termination_status) ||
3613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      termination_status < 0 ||
3623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      termination_status >= base::TERMINATION_STATUS_MAX_ENUM) {
3633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetTerminationStatus: pickle failed";
3643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int remote_exit_code;
3683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&remote_exit_code)) {
3693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetTerminationStatus: pickle failed";
3703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *status = static_cast<base::TerminationStatus>(termination_status);
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *exit_code = remote_exit_code;
3753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
3763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
377