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