// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sandbox/mac/pre_exec_delegate.h" #include #include #include #include "base/logging.h" #include "base/mac/mac_util.h" #include "sandbox/mac/bootstrap_sandbox.h" #include "sandbox/mac/xpc.h" namespace sandbox { PreExecDelegate::PreExecDelegate( const std::string& sandbox_server_bootstrap_name, uint64_t sandbox_token) : sandbox_server_bootstrap_name_(sandbox_server_bootstrap_name), sandbox_server_bootstrap_name_ptr_( sandbox_server_bootstrap_name_.c_str()), sandbox_token_(sandbox_token), is_yosemite_or_later_(base::mac::IsOSYosemiteOrLater()), look_up_message_(CreateBootstrapLookUpMessage()) { } PreExecDelegate::~PreExecDelegate() {} void PreExecDelegate::RunAsyncSafe() { mach_port_t sandbox_server_port = MACH_PORT_NULL; kern_return_t kr = DoBootstrapLookUp(&sandbox_server_port); if (kr != KERN_SUCCESS) RAW_LOG(FATAL, "Failed to look up bootstrap sandbox server port."); mach_port_t new_bootstrap_port = MACH_PORT_NULL; if (!BootstrapSandbox::ClientCheckIn(sandbox_server_port, sandbox_token_, &new_bootstrap_port)) { RAW_LOG(FATAL, "Failed to check in with sandbox server."); } kr = task_set_bootstrap_port(mach_task_self(), new_bootstrap_port); if (kr != KERN_SUCCESS) RAW_LOG(FATAL, "Failed to replace bootstrap port."); // On OS X 10.10 and higher, libxpc uses the port stash to transfer the // XPC root port. This is effectively the same connection as the Mach // bootstrap port, but not transferred using the task special port. // Therefore, stash the replacement bootstrap port, so that on 10.10 it // will be retrieved by the XPC code and used as a replacement for the // XPC root port as well. if (is_yosemite_or_later_) { kr = mach_ports_register(mach_task_self(), &new_bootstrap_port, 1); if (kr != KERN_SUCCESS) RAW_LOG(ERROR, "Failed to register replacement bootstrap port."); } } xpc_object_t PreExecDelegate::CreateBootstrapLookUpMessage() { if (is_yosemite_or_later_) { xpc_object_t dictionary = xpc_dictionary_create(nullptr, nullptr, 0); xpc_dictionary_set_uint64(dictionary, "type", 7); xpc_dictionary_set_uint64(dictionary, "handle", 0); xpc_dictionary_set_string(dictionary, "name", sandbox_server_bootstrap_name_ptr_); xpc_dictionary_set_int64(dictionary, "targetpid", 0); xpc_dictionary_set_uint64(dictionary, "flags", 0); xpc_dictionary_set_uint64(dictionary, "subsystem", 5); xpc_dictionary_set_uint64(dictionary, "routine", 207); // Add a NULL port so that the slot in the dictionary is already // allocated. xpc_dictionary_set_mach_send(dictionary, "domain-port", MACH_PORT_NULL); return dictionary; } return nullptr; } kern_return_t PreExecDelegate::DoBootstrapLookUp(mach_port_t* out_port) { if (is_yosemite_or_later_) { xpc_dictionary_set_mach_send(look_up_message_, "domain-port", bootstrap_port); // |pipe| cannot be created pre-fork() since the |bootstrap_port| will // be invalidated. Deliberately leak |pipe| as well. xpc_pipe_t pipe = xpc_pipe_create_from_port(bootstrap_port, 0); xpc_object_t reply; int rv = xpc_pipe_routine(pipe, look_up_message_, &reply); if (rv != 0) { return xpc_dictionary_get_int64(reply, "error"); } else { xpc_object_t port_value = xpc_dictionary_get_value(reply, "port"); *out_port = xpc_mach_send_get_right(port_value); return *out_port != MACH_PORT_NULL ? KERN_SUCCESS : KERN_INVALID_RIGHT; } } else { // On non-XPC launchd systems, bootstrap_look_up() is MIG-based and // generally safe. return bootstrap_look_up(bootstrap_port, sandbox_server_bootstrap_name_ptr_, out_port); } } } // namespace sandbox