summaryrefslogtreecommitdiffstats
path: root/sandbox
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-03 10:48:26 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-03 10:48:26 +0000
commitcdd0be1b2d639a31eae9acbb49771653ec86510f (patch)
treedbe55a59ac16560d5aefe74a3d90f7cbec171b34 /sandbox
parent98e5a9e1c8c1dd1931850a4e0bd99124c67d3c95 (diff)
downloadchromium_src-cdd0be1b2d639a31eae9acbb49771653ec86510f.zip
chromium_src-cdd0be1b2d639a31eae9acbb49771653ec86510f.tar.gz
chromium_src-cdd0be1b2d639a31eae9acbb49771653ec86510f.tar.bz2
Do not double-unref send rights when using POLICY_SUBSTITUE_PORT.
By destroying the reply message, the already-copied-out right will be unrefed again, leading to an over-release of send rights. This also requires that Rule(POLICY_SUBSTITUTE_PORT) users provide a send right that can be duplicated with MACH_MSG_TYPE_COPY_SEND, rather than using MAKE_SEND. BUG=367863 R=mark@chromium.org Review URL: https://codereview.chromium.org/306123012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274467 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r--sandbox/mac/bootstrap_sandbox_unittest.mm25
-rw-r--r--sandbox/mac/launchd_interception_server.cc29
-rw-r--r--sandbox/mac/launchd_interception_server.h7
-rw-r--r--sandbox/mac/os_compatibility.cc2
-rw-r--r--sandbox/mac/policy.h3
5 files changed, 47 insertions, 19 deletions
diff --git a/sandbox/mac/bootstrap_sandbox_unittest.mm b/sandbox/mac/bootstrap_sandbox_unittest.mm
index 8bfbf32..f8d8165b 100644
--- a/sandbox/mac/bootstrap_sandbox_unittest.mm
+++ b/sandbox/mac/bootstrap_sandbox_unittest.mm
@@ -225,11 +225,27 @@ struct SubstitutePortAckRecv : public SubstitutePortAckSend {
const char kSubstituteAck[] = "Hello, this is doge!";
TEST_F(BootstrapSandboxTest, PolicySubstitutePort) {
+ mach_port_t task = mach_task_self();
+
mach_port_t port;
- ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
- MACH_PORT_RIGHT_RECEIVE, &port));
+ ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE,
+ &port));
base::mac::ScopedMachReceiveRight scoped_port(port);
+ mach_port_urefs_t send_rights = 0;
+ ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+ &send_rights));
+ EXPECT_EQ(0u, send_rights);
+
+ ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(task, port, port,
+ MACH_MSG_TYPE_MAKE_SEND));
+ base::mac::ScopedMachSendRight scoped_port_send(port);
+
+ send_rights = 0;
+ ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+ &send_rights));
+ EXPECT_EQ(1u, send_rights);
+
BootstrapSandboxPolicy policy(BaselinePolicy());
policy[kTestServer] = Rule(port);
sandbox_->RegisterSandboxPolicy(1, policy);
@@ -245,6 +261,11 @@ TEST_F(BootstrapSandboxTest, PolicySubstitutePort) {
TestTimeouts::tiny_timeout().InMilliseconds(), MACH_PORT_NULL);
EXPECT_EQ(KERN_SUCCESS, kr);
+ send_rights = 0;
+ ASSERT_EQ(KERN_SUCCESS, mach_port_get_refs(task, port, MACH_PORT_RIGHT_SEND,
+ &send_rights));
+ EXPECT_EQ(1u, send_rights);
+
EXPECT_EQ(0, strncmp(kSubstituteAck, msg.buf, sizeof(msg.buf)));
}
diff --git a/sandbox/mac/launchd_interception_server.cc b/sandbox/mac/launchd_interception_server.cc
index 919f207..3cb1821 100644
--- a/sandbox/mac/launchd_interception_server.cc
+++ b/sandbox/mac/launchd_interception_server.cc
@@ -76,6 +76,12 @@ bool LaunchdInterceptionServer::Initialize() {
return false;
}
sandbox_port_.reset(port);
+ if ((kr = mach_port_insert_right(task, sandbox_port_, sandbox_port_,
+ MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS)) {
+ MACH_LOG(ERROR, kr) << "Failed to allocate dummy sandbox port send right.";
+ return false;
+ }
+ sandbox_send_port_.reset(sandbox_port_);
// Set up the dispatch queue to service the bootstrap port.
// TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL means
@@ -216,16 +222,13 @@ void LaunchdInterceptionServer::HandleLookUp(mach_msg_header_t* request,
else
result_port = rule.substitute_port;
- // Grant an additional send right on the result_port so that it can be
- // sent to the sandboxed child process.
- kern_return_t kr = mach_port_insert_right(mach_task_self(),
- result_port, result_port, MACH_MSG_TYPE_MAKE_SEND);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "Unable to insert right on result_port.";
- }
-
compat_shim_.look_up2_fill_reply(reply, result_port);
- SendReply(reply);
+ // If the message was sent successfully, clear the result_port out of the
+ // message so that it is not destroyed at the end of ReceiveMessage. The
+ // above-inserted right has been moved out of the process, and destroying
+ // the message will unref yet another right.
+ if (SendReply(reply))
+ compat_shim_.look_up2_fill_reply(reply, MACH_PORT_NULL);
} else {
NOTREACHED();
}
@@ -246,12 +249,12 @@ void LaunchdInterceptionServer::HandleSwapInteger(mach_msg_header_t* request,
}
}
-void LaunchdInterceptionServer::SendReply(mach_msg_header_t* reply) {
+bool LaunchdInterceptionServer::SendReply(mach_msg_header_t* reply) {
kern_return_t kr = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0,
MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
- if (kr != KERN_SUCCESS) {
- MACH_LOG(ERROR, kr) << "Unable to send intercepted reply message.";
- }
+ MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+ << "Unable to send intercepted reply message.";
+ return kr == KERN_SUCCESS;
}
void LaunchdInterceptionServer::ForwardMessage(mach_msg_header_t* request,
diff --git a/sandbox/mac/launchd_interception_server.h b/sandbox/mac/launchd_interception_server.h
index 6b92e9f..1176533 100644
--- a/sandbox/mac/launchd_interception_server.h
+++ b/sandbox/mac/launchd_interception_server.h
@@ -54,8 +54,8 @@ class LaunchdInterceptionServer {
mach_msg_header_t* reply,
pid_t sender_pid);
- // Sends a reply message.
- void SendReply(mach_msg_header_t* reply);
+ // Sends a reply message. Returns true if the message was sent successfully.
+ bool SendReply(mach_msg_header_t* reply);
// Forwards the original |request| on to real bootstrap server for handling.
void ForwardMessage(mach_msg_header_t* request, mach_msg_header_t* reply);
@@ -88,6 +88,9 @@ class LaunchdInterceptionServer {
// The Mach port handed out in reply to denied look up requests. All denied
// requests share the same port, though nothing reads messages from it.
base::mac::ScopedMachReceiveRight sandbox_port_;
+ // The send right for the above |sandbox_port_|, used with
+ // MACH_MSG_TYPE_COPY_SEND when handing out references to the dummy port.
+ base::mac::ScopedMachSendRight sandbox_send_port_;
// The compatibility shim that handles differences in message header IDs and
// request/reply structures between different OS X versions.
diff --git a/sandbox/mac/os_compatibility.cc b/sandbox/mac/os_compatibility.cc
index 3285756..be0ca3e 100644
--- a/sandbox/mac/os_compatibility.cc
+++ b/sandbox/mac/os_compatibility.cc
@@ -87,7 +87,7 @@ void LaunchdLookUp2FillReply(mach_msg_header_t* header, mach_port_t port) {
MACH_MSGH_BITS_COMPLEX;
reply->msgh_body.msgh_descriptor_count = 1;
reply->service_port.name = port;
- reply->service_port.disposition = MACH_MSG_TYPE_PORT_SEND;
+ reply->service_port.disposition = MACH_MSG_TYPE_COPY_SEND;
reply->service_port.type = MACH_MSG_PORT_DESCRIPTOR;
}
diff --git a/sandbox/mac/policy.h b/sandbox/mac/policy.h
index 01ea85a..0cedcb8 100644
--- a/sandbox/mac/policy.h
+++ b/sandbox/mac/policy.h
@@ -42,7 +42,8 @@ struct SANDBOX_EXPORT Rule {
PolicyDecision result;
// The Rule does not take ownership of this port, but additional send rights
- // will be allocated to it before it is sent to a client.
+ // will be allocated to it before it is sent to a client. This name must
+ // denote a send right that can duplicated with MACH_MSG_TYPE_COPY_SEND.
mach_port_t substitute_port;
};