Skip to content

Commit

Permalink
On 10.10+, do not use bootstrap_look_up() directly.
Browse files Browse the repository at this point in the history
XPC performs a lot of potentially async-signal-unsafe allocations under the
hood, making it unsuitable for use in sandbox::PreExecDelegate. By manually
allocating the XPC message, attempt to avoid these allocations.

BUG=537618
R=mark@chromium.org

Review URL: https://codereview.chromium.org/1376583004

Cr-Commit-Position: refs/heads/master@{#351601}
  • Loading branch information
rsesek authored and Commit bot committed Sep 30, 2015
1 parent 58bf1f8 commit e624db4
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 3 deletions.
52 changes: 49 additions & 3 deletions sandbox/mac/pre_exec_delegate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "sandbox/mac/bootstrap_sandbox.h"
#include "sandbox/mac/xpc.h"

namespace sandbox {

Expand All @@ -20,15 +21,15 @@ PreExecDelegate::PreExecDelegate(
sandbox_server_bootstrap_name_ptr_(
sandbox_server_bootstrap_name_.c_str()),
sandbox_token_(sandbox_token),
is_yosemite_or_later_(base::mac::IsOSYosemiteOrLater()) {
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 = bootstrap_look_up(bootstrap_port,
sandbox_server_bootstrap_name_ptr_, &sandbox_server_port);
kern_return_t kr = DoBootstrapLookUp(&sandbox_server_port);
if (kr != KERN_SUCCESS)
RAW_LOG(FATAL, "Failed to look up bootstrap sandbox server port.");

Expand Down Expand Up @@ -56,4 +57,49 @@ void PreExecDelegate::RunAsyncSafe() {
}
}

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
13 changes: 13 additions & 0 deletions sandbox/mac/pre_exec_delegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define SANDBOX_MAC_PRE_EXEC_DELEGATE_H_

#include "base/process/launch.h"
#include "sandbox/mac/xpc.h"

namespace sandbox {

Expand All @@ -24,11 +25,23 @@ class PreExecDelegate : public base::LaunchOptions::PreExecDelegate {
uint64_t sandbox_token() const { return sandbox_token_; }

private:
// Allocates the bootstrap_look_up IPC message prior to fork().
xpc_object_t CreateBootstrapLookUpMessage();

// Performs a bootstrap_look_up(), either using the pre-allocated message
// or the normal routine, depending on the OS X system version.
kern_return_t DoBootstrapLookUp(mach_port_t* out_port);

const std::string sandbox_server_bootstrap_name_;
const char* const sandbox_server_bootstrap_name_ptr_;
const uint64_t sandbox_token_;
const bool is_yosemite_or_later_;

// If is_yosemite_or_later_, this field is used to hold the pre-allocated XPC
// object needed to interact with the bootstrap server in RunAsyncSafe().
// This is deliberately leaked in the fork()ed process.
xpc_object_t look_up_message_;

DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
};

Expand Down
3 changes: 3 additions & 0 deletions sandbox/mac/xpc_private_stubs.sig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
void xpc_dictionary_set_mach_send(xpc_object_t dictionary, const char* name, mach_port_t port);
void xpc_dictionary_get_audit_token(xpc_object_t dictionary, audit_token_t* token);

// Raw object getters.
mach_port_t xpc_mach_send_get_right(xpc_object_t value);

// Pipe methods.
xpc_pipe_t xpc_pipe_create_from_port(mach_port_t port, int flags);
int xpc_pipe_receive(mach_port_t port, xpc_object_t* message);
Expand Down
7 changes: 7 additions & 0 deletions sandbox/mac/xpc_stubs_header.fragment
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ xpc_dictionary_get_uint64(xpc_object_t xdict, const char* key);
XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2 void
xpc_dictionary_set_uint64(xpc_object_t xdict, const char* key, uint64_t value);

XPC_EXPORT XPC_NONNULL1 XPC_NONNULL2
void xpc_dictionary_set_string(xpc_object_t xdict, const char* key,
const char* string);

XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT xpc_object_t
xpc_dictionary_create(const char* const* keys,
const xpc_object_t* values,
Expand All @@ -61,6 +65,9 @@ XPC_EXPORT XPC_MALLOC XPC_RETURNS_RETAINED XPC_WARN_RESULT XPC_NONNULL_ALL
xpc_object_t
xpc_dictionary_create_reply(xpc_object_t original);

XPC_EXPORT XPC_WARN_RESULT XPC_NONNULL1 XPC_NONNULL2
xpc_object_t xpc_dictionary_get_value(xpc_object_t xdict, const char* key);

XPC_EXPORT XPC_MALLOC XPC_WARN_RESULT XPC_NONNULL1
char* xpc_copy_description(xpc_object_t object);
} // extern "C"
Expand Down

0 comments on commit e624db4

Please sign in to comment.