rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 1 | // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "sandbox/mac/pre_exec_delegate.h" |
| 6 | |
| 7 | #include <mach/mach.h> |
| 8 | #include <servers/bootstrap.h> |
avi | 74a1875f | 2015-12-22 02:10:03 | [diff] [blame] | 9 | #include <stdint.h> |
rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 10 | |
| 11 | #include "base/logging.h" |
| 12 | #include "base/mac/mac_util.h" |
| 13 | #include "sandbox/mac/bootstrap_sandbox.h" |
rsesek | e624db4 | 2015-09-30 18:18:08 | [diff] [blame] | 14 | #include "sandbox/mac/xpc.h" |
rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 15 | |
| 16 | namespace sandbox { |
| 17 | |
| 18 | PreExecDelegate::PreExecDelegate( |
| 19 | const std::string& sandbox_server_bootstrap_name, |
| 20 | uint64_t sandbox_token) |
| 21 | : sandbox_server_bootstrap_name_(sandbox_server_bootstrap_name), |
| 22 | sandbox_server_bootstrap_name_ptr_( |
| 23 | sandbox_server_bootstrap_name_.c_str()), |
| 24 | sandbox_token_(sandbox_token), |
sdy | 07171a4 | 2016-08-30 18:22:04 | [diff] [blame] | 25 | is_yosemite_or_later_(base::mac::IsAtLeastOS10_10()), |
| 26 | look_up_message_(CreateBootstrapLookUpMessage()) {} |
rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 27 | |
| 28 | PreExecDelegate::~PreExecDelegate() {} |
| 29 | |
| 30 | void PreExecDelegate::RunAsyncSafe() { |
| 31 | mach_port_t sandbox_server_port = MACH_PORT_NULL; |
rsesek | e624db4 | 2015-09-30 18:18:08 | [diff] [blame] | 32 | kern_return_t kr = DoBootstrapLookUp(&sandbox_server_port); |
rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 33 | if (kr != KERN_SUCCESS) |
| 34 | RAW_LOG(FATAL, "Failed to look up bootstrap sandbox server port."); |
| 35 | |
| 36 | mach_port_t new_bootstrap_port = MACH_PORT_NULL; |
| 37 | if (!BootstrapSandbox::ClientCheckIn(sandbox_server_port, |
| 38 | sandbox_token_, |
| 39 | &new_bootstrap_port)) { |
| 40 | RAW_LOG(FATAL, "Failed to check in with sandbox server."); |
| 41 | } |
| 42 | |
| 43 | kr = task_set_bootstrap_port(mach_task_self(), new_bootstrap_port); |
| 44 | if (kr != KERN_SUCCESS) |
| 45 | RAW_LOG(FATAL, "Failed to replace bootstrap port."); |
| 46 | |
| 47 | // On OS X 10.10 and higher, libxpc uses the port stash to transfer the |
| 48 | // XPC root port. This is effectively the same connection as the Mach |
| 49 | // bootstrap port, but not transferred using the task special port. |
| 50 | // Therefore, stash the replacement bootstrap port, so that on 10.10 it |
| 51 | // will be retrieved by the XPC code and used as a replacement for the |
| 52 | // XPC root port as well. |
| 53 | if (is_yosemite_or_later_) { |
| 54 | kr = mach_ports_register(mach_task_self(), &new_bootstrap_port, 1); |
| 55 | if (kr != KERN_SUCCESS) |
| 56 | RAW_LOG(ERROR, "Failed to register replacement bootstrap port."); |
| 57 | } |
| 58 | } |
| 59 | |
rsesek | e624db4 | 2015-09-30 18:18:08 | [diff] [blame] | 60 | xpc_object_t PreExecDelegate::CreateBootstrapLookUpMessage() { |
| 61 | if (is_yosemite_or_later_) { |
| 62 | xpc_object_t dictionary = xpc_dictionary_create(nullptr, nullptr, 0); |
| 63 | xpc_dictionary_set_uint64(dictionary, "type", 7); |
| 64 | xpc_dictionary_set_uint64(dictionary, "handle", 0); |
| 65 | xpc_dictionary_set_string(dictionary, "name", |
| 66 | sandbox_server_bootstrap_name_ptr_); |
| 67 | xpc_dictionary_set_int64(dictionary, "targetpid", 0); |
| 68 | xpc_dictionary_set_uint64(dictionary, "flags", 0); |
| 69 | xpc_dictionary_set_uint64(dictionary, "subsystem", 5); |
| 70 | xpc_dictionary_set_uint64(dictionary, "routine", 207); |
| 71 | // Add a NULL port so that the slot in the dictionary is already |
| 72 | // allocated. |
| 73 | xpc_dictionary_set_mach_send(dictionary, "domain-port", MACH_PORT_NULL); |
| 74 | return dictionary; |
| 75 | } |
| 76 | |
| 77 | return nullptr; |
| 78 | } |
| 79 | |
| 80 | kern_return_t PreExecDelegate::DoBootstrapLookUp(mach_port_t* out_port) { |
| 81 | if (is_yosemite_or_later_) { |
| 82 | xpc_dictionary_set_mach_send(look_up_message_, "domain-port", |
| 83 | bootstrap_port); |
| 84 | |
| 85 | // |pipe| cannot be created pre-fork() since the |bootstrap_port| will |
| 86 | // be invalidated. Deliberately leak |pipe| as well. |
| 87 | xpc_pipe_t pipe = xpc_pipe_create_from_port(bootstrap_port, 0); |
| 88 | xpc_object_t reply; |
| 89 | int rv = xpc_pipe_routine(pipe, look_up_message_, &reply); |
| 90 | if (rv != 0) { |
| 91 | return xpc_dictionary_get_int64(reply, "error"); |
| 92 | } else { |
| 93 | xpc_object_t port_value = xpc_dictionary_get_value(reply, "port"); |
| 94 | *out_port = xpc_mach_send_get_right(port_value); |
| 95 | return *out_port != MACH_PORT_NULL ? KERN_SUCCESS : KERN_INVALID_RIGHT; |
| 96 | } |
| 97 | } else { |
| 98 | // On non-XPC launchd systems, bootstrap_look_up() is MIG-based and |
| 99 | // generally safe. |
| 100 | return bootstrap_look_up(bootstrap_port, |
| 101 | sandbox_server_bootstrap_name_ptr_, out_port); |
| 102 | } |
| 103 | } |
| 104 | |
rsesek | 408d2ee5 | 2015-09-18 01:18:04 | [diff] [blame] | 105 | } // namespace sandbox |