nacl_fork_delegate_linux.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/pickle.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/eintr_wrapper.h"
224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/posix/global_descriptors.h"
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/posix/unix_domain_socket_linux.h"
243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/process/kill.h"
2558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/launch.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
27a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "components/nacl/common/nacl_paths.h"
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "components/nacl/common/nacl_switches.h"
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/nacl/loader/nacl_helper_linux.h"
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "content/public/common/content_descriptors.h"
31d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch#include "content/public/common/content_switches.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace {
34ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Note these need to match up with their counterparts in nacl_helper_linux.c
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// and nacl_helper_bootstrap_linux.c.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNaClHelperReservedAtZero[] =
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    "--reserved_at_zero=0xXXXXXXXXXXXXXXXX";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kNaClHelperRDebug[] = "--r_debug=0xXXXXXXXXXXXXXXXX";
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
41bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#if defined(ARCH_CPU_X86)
42bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdochbool NonZeroSegmentBaseIsSlow() {
43bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  base::CPU cpuid;
44bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Using a non-zero segment base is known to be very slow on Intel
45bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Atom CPUs.  See "Segmentation-based Memory Protection Mechanism
46bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // on Intel Atom Microarchitecture: Coding Optimizations" (Leonardo
47bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Potenza, Intel).
48bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //
49bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // The following list of CPU model numbers is taken from:
50bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // "Intel 64 and IA-32 Architectures Software Developer's Manual"
51bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // (http://download.intel.com/products/processor/manual/325462.pdf),
52bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // "Table 35-1. CPUID Signature Values of DisplayFamily_DisplayModel"
53bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // (Volume 3C, 35-1), which contains:
54bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //   "06_36H - Intel Atom S Processor Family
55bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //    06_1CH, 06_26H, 06_27H, 06_35, 06_36 - Intel Atom Processor Family"
56bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  if (cpuid.family() == 6) {
57bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    switch (cpuid.model()) {
58bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x1c:
59bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x26:
60bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x27:
61bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x35:
62bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      case 0x36:
63bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        return true;
64bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
65bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  }
66bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  return false;
67bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch}
68bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#endif
69bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// Send an IPC request on |ipc_channel|. The request is contained in
713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |request_pickle| and can have file descriptors attached in |attached_fds|.
723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// |reply_data_buffer| must be allocated by the caller and will contain the
733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// reply. The size of the reply will be written to |reply_size|.
743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// This code assumes that only one thread can write to |ipc_channel| to make
753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// requests.
763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool SendIPCRequestAndReadReply(int ipc_channel,
773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const std::vector<int>& attached_fds,
783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                const Pickle& request_pickle,
793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                char* reply_data_buffer,
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                size_t reply_data_buffer_size,
813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                ssize_t* reply_size) {
823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK_LE(static_cast<size_t>(kNaClMaxIPCMessageLength),
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            reply_data_buffer_size);
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(reply_size);
853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!UnixDomainSocket::SendMsg(ipc_channel, request_pickle.data(),
873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 request_pickle.size(), attached_fds)) {
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "SendIPCRequestAndReadReply: SendMsg failed";
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Then read the remote reply.
933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  std::vector<int> received_fds;
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const ssize_t msg_len =
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      UnixDomainSocket::RecvMsg(ipc_channel, reply_data_buffer,
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                reply_data_buffer_size, &received_fds);
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (msg_len <= 0) {
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "SendIPCRequestAndReadReply: RecvMsg failed";
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *reply_size = msg_len;
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
105d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch}  // namespace.
106ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
107ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochNaClForkDelegate::NaClForkDelegate()
108ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    : status_(kNaClHelperUnused),
109ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch      fd_(-1) {}
110ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void NaClForkDelegate::Init(const int sandboxdesc) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::Init()";
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int fds[2];
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // For communications between the NaCl loader process and
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // the SUID sandbox.
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  int nacl_sandbox_descriptor =
1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Confirm a hard-wired assumption.
1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK_EQ(sandboxdesc, nacl_sandbox_descriptor);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(socketpair(PF_UNIX, SOCK_SEQPACKET, 0, fds) == 0);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FileHandleMappingVector fds_to_map;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fds_to_map.push_back(std::make_pair(fds[1], kNaClZygoteDescriptor));
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  fds_to_map.push_back(std::make_pair(sandboxdesc, nacl_sandbox_descriptor));
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Using nacl_helper_bootstrap is not necessary on x86-64 because
128bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // NaCl's x86-64 sandbox is not zero-address-based.  Starting
129bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // nacl_helper through nacl_helper_bootstrap works on x86-64, but it
130bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // leaves nacl_helper_bootstrap mapped at a fixed address at the
131bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // bottom of the address space, which is undesirable because it
132bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // effectively defeats ASLR.
133bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#if defined(ARCH_CPU_X86_64)
134bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = false;
135bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#elif defined(ARCH_CPU_X86)
136bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Performance vs. security trade-off: We prefer using a
137bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // non-zero-address-based sandbox on x86-32 because it provides some
138bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // ASLR and so is more secure.  However, on Atom CPUs, using a
139bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // non-zero segment base is very slow, so we use a zero-based
140bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // sandbox on those.
141bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = NonZeroSegmentBaseIsSlow();
142bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#else
143bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  bool kUseNaClBootstrap = true;
144bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#endif
145bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  status_ = kNaClHelperUnused;
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath helper_exe;
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath helper_bootstrap_exe;
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!PathService::Get(nacl::FILE_NACL_HELPER, &helper_exe)) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperMissing;
151ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  } else if (kUseNaClBootstrap &&
152ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch             !PathService::Get(nacl::FILE_NACL_HELPER_BOOTSTRAP,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               &helper_bootstrap_exe)) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperBootstrapMissing;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (RunningOnValgrind()) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperValgrind;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
158d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    CommandLine::StringVector argv_to_launch;
159d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    {
160d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      CommandLine cmd_line(CommandLine::NO_PROGRAM);
161d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      if (kUseNaClBootstrap)
162d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        cmd_line.SetProgram(helper_bootstrap_exe);
163d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      else
164d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        cmd_line.SetProgram(helper_exe);
165d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
166d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Append any switches that need to be forwarded to the NaCl helper.
167d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      static const char* kForwardSwitches[] = {
168d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switches::kDisableSeccompFilterSandbox,
169d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        switches::kNoSandbox,
170d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      };
171d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      const CommandLine& current_cmd_line = *CommandLine::ForCurrentProcess();
172d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      cmd_line.CopySwitchesFrom(current_cmd_line, kForwardSwitches,
173d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                                arraysize(kForwardSwitches));
174d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch
175d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // The command line needs to be tightly controlled to use
176d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // |helper_bootstrap_exe|. So from now on, argv_to_launch should be
177d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // modified directly.
178d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      argv_to_launch = cmd_line.argv();
179d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    }
180ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (kUseNaClBootstrap) {
181d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // Arguments to the bootstrap helper which need to be at the start
182d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      // of the command line, right after the helper's path.
183d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      CommandLine::StringVector bootstrap_prepend;
184d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(helper_exe.value());
185d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(kNaClHelperReservedAtZero);
186d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      bootstrap_prepend.push_back(kNaClHelperRDebug);
187d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch      argv_to_launch.insert(argv_to_launch.begin() + 1,
188d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            bootstrap_prepend.begin(),
189d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch                            bootstrap_prepend.end());
190ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    }
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::LaunchOptions options;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.fds_to_remap = &fds_to_map;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.clone_flags = CLONE_FS | SIGCHLD;
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The NaCl processes spawned may need to exceed the ambient soft limit
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // on RLIMIT_AS to allocate the untrusted address space and its guard
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // regions.  The nacl_helper itself cannot just raise its own limit,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // because the existing limit may prevent the initial exec of
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // nacl_helper_bootstrap from succeeding, with its large address space
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // reservation.
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::vector<int> max_these_limits;
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    max_these_limits.push_back(RLIMIT_AS);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    options.maximize_rlimits = &max_these_limits;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch    if (!base::LaunchProcess(argv_to_launch, options, NULL))
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = kNaClHelperLaunchFailed;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // parent and error cases are handled below
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IGNORE_EINTR(close(fds[1])) != 0)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "close(fds[1]) failed";
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == kNaClHelperUnused) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ssize_t kExpectedLength = strlen(kNaClHelperStartupAck);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char buf[kExpectedLength];
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Wait for ack from nacl_helper, indicating it is ready to help
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const ssize_t nread = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (nread == kExpectedLength &&
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        memcmp(buf, kNaClHelperStartupAck, nread) == 0) {
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // all is well
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      status_ = kNaClHelperSuccess;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fd_ = fds[0];
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    status_ = kNaClHelperAckFailed;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Bad NaCl helper startup ack (" << nread << " bytes)";
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(bradchen): Make this LOG(ERROR) when the NaCl helper
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // becomes the default.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fd_ = -1;
231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (IGNORE_EINTR(close(fds[0])) != 0)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "close(fds[0]) failed";
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void NaClForkDelegate::InitialUMA(std::string* uma_name,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int* uma_sample,
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  int* uma_boundary_value) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_name = "NaCl.Client.Helper.InitState";
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_sample = status_;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_boundary_value = kNaClHelperStatusBoundary;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NaClForkDelegate::~NaClForkDelegate() {
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // side effect of close: delegate process will terminate
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (status_ == kNaClHelperSuccess) {
246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IGNORE_EINTR(close(fd_)) != 0)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "close(fd_) failed";
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClForkDelegate::CanHelp(const std::string& process_type,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               std::string* uma_name,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* uma_sample,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               int* uma_boundary_value) {
255e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (process_type != switches::kNaClLoaderProcess &&
256e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      process_type != switches::kNaClLoaderNonSfiProcess)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_name = "NaCl.Client.Helper.StateOnFork";
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_sample = status_;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *uma_boundary_value = kNaClHelperStatusBoundary;
2611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return true;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
264e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochpid_t NaClForkDelegate::Fork(const std::string& process_type,
265e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                             const std::vector<int>& fds) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::Fork";
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(fds.size() == kNumPassedFDs);
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (status_ != kNaClHelperSuccess) {
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    LOG(ERROR) << "Cannot launch NaCl process: nacl_helper failed to start";
2721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return -1;
2731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
2741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // First, send a remote fork request.
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle write_pickle;
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  write_pickle.WriteInt(nacl::kNaClForkRequest);
278e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // TODO(hamaji): When we split the helper binary for non-SFI mode
279e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // from nacl_helper, stop sending this information.
280e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  const bool uses_nonsfi_mode =
281e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    process_type == switches::kNaClLoaderNonSfiProcess;
282e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  write_pickle.WriteBool(uses_nonsfi_mode);
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char reply_buf[kNaClMaxIPCMessageLength];
2853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ssize_t reply_size = 0;
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool got_reply =
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      SendIPCRequestAndReadReply(fd_, fds, write_pickle,
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 reply_buf, sizeof(reply_buf), &reply_size);
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!got_reply) {
2903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Could not perform remote fork.";
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Now see if the other end managed to fork.
2953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle reply_pickle(reply_buf, reply_size);
2963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PickleIterator iter(reply_pickle);
2973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  pid_t nacl_child;
2983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&nacl_child)) {
2993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "NaClForkDelegate::Fork: pickle failed";
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(1) << "nacl_child is " << nacl_child;
3033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return nacl_child;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool NaClForkDelegate::AckChild(const int fd,
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& channel_switch) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nwritten = HANDLE_EINTR(write(fd, channel_switch.c_str(),
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    channel_switch.length()));
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (nwritten != static_cast<int>(channel_switch.length())) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)bool NaClForkDelegate::GetTerminationStatus(pid_t pid, bool known_dead,
3173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            base::TerminationStatus* status,
3183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                            int* exit_code) {
3193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  VLOG(1) << "NaClForkDelegate::GetTerminationStatus";
3203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(status);
3213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DCHECK(exit_code);
3223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle write_pickle;
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  write_pickle.WriteInt(nacl::kNaClGetTerminationStatusRequest);
3253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  write_pickle.WriteInt(pid);
3263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  write_pickle.WriteBool(known_dead);
3273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  const std::vector<int> empty_fds;
3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  char reply_buf[kNaClMaxIPCMessageLength];
3303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ssize_t reply_size = 0;
3313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool got_reply =
3323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      SendIPCRequestAndReadReply(fd_, empty_fds, write_pickle,
3333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                                 reply_buf, sizeof(reply_buf), &reply_size);
3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!got_reply) {
3353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "Could not perform remote GetTerminationStatus.";
3363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  Pickle reply_pickle(reply_buf, reply_size);
3403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  PickleIterator iter(reply_pickle);
3413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int termination_status;
3423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&termination_status) ||
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      termination_status < 0 ||
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      termination_status >= base::TERMINATION_STATUS_MAX_ENUM) {
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetTerminationStatus: pickle failed";
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int remote_exit_code;
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!iter.ReadInt(&remote_exit_code)) {
3513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    LOG(ERROR) << "GetTerminationStatus: pickle failed";
3523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
3533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
3543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *status = static_cast<base::TerminationStatus>(termination_status);
3563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  *exit_code = remote_exit_code;
3573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return true;
3583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
359