summaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorerikchen <erikchen@chromium.org>2015-11-11 14:07:27 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-11 22:09:02 +0000
commit7c556436847923c1d90b557c9fa4a8b7b1ab8d21 (patch)
tree1032a61ab02babda469b2d7b0f83b0325b117080 /ipc
parent6559593ee87549fd2be3cf96d512890d3eaf404c (diff)
downloadchromium_src-7c556436847923c1d90b557c9fa4a8b7b1ab8d21.zip
chromium_src-7c556436847923c1d90b557c9fa4a8b7b1ab8d21.tar.gz
chromium_src-7c556436847923c1d90b557c9fa4a8b7b1ab8d21.tar.bz2
mac: The attachment broker waits for the port provider before brokering.
Previously, the attachment broker assumed that the port provider would have the task port for the relevant processes. There is a race condition where a message may need to be brokered before the port provider has received the task port, which would cause attachment brokering failures. This CL creates intermediaries in the attachment broker (AttachmentPrecursor, AttachmentExtractor) which hold all the information necessary to broker an attachment. BUG=550938 Review URL: https://codereview.chromium.org/1416213005 Cr-Commit-Position: refs/heads/master@{#359167}
Diffstat (limited to 'ipc')
-rw-r--r--ipc/attachment_broker_mac_unittest.cc152
-rw-r--r--ipc/attachment_broker_privileged.h6
-rw-r--r--ipc/attachment_broker_privileged_mac.cc227
-rw-r--r--ipc/attachment_broker_privileged_mac.h113
-rw-r--r--ipc/attachment_broker_privileged_mac_unittest.cc18
-rw-r--r--ipc/ipc_channel_reader.cc1
-rw-r--r--ipc/ipc_test_messages.h2
7 files changed, 428 insertions, 91 deletions
diff --git a/ipc/attachment_broker_mac_unittest.cc b/ipc/attachment_broker_mac_unittest.cc
index 3188640..2e370cd 100644
--- a/ipc/attachment_broker_mac_unittest.cc
+++ b/ipc/attachment_broker_mac_unittest.cc
@@ -14,6 +14,7 @@
#include "base/mac/mac_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
+#include "ipc/attachment_broker_messages.h"
#include "ipc/attachment_broker_privileged_mac.h"
#include "ipc/attachment_broker_unprivileged_mac.h"
#include "ipc/ipc_listener.h"
@@ -348,8 +349,11 @@ class MockPortProvider : public base::PortProvider {
void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
port_map_[process] = task_port;
+ NotifyObservers(process);
}
+ void ClearPortMap() { port_map_.clear(); }
+
private:
std::map<base::ProcessHandle, mach_port_t> port_map_;
};
@@ -466,17 +470,23 @@ class IPCAttachmentBrokerMacTest : public IPCTestBase {
ResultListener result_listener_;
};
-using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
- const IPC::Message& message);
-
// These objects are globally accessible, and are expected to outlive all IPC
// Channels.
struct ChildProcessGlobals {
- scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
MockPortProvider port_provider;
+
+ // The broker must be destroyed before the port_provider, so that the broker
+ // gets a chance to unregister itself as an observer. This doesn't matter
+ // outside of tests, since neither port_provider nor broker will ever be
+ // destroyed.
+ scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
base::mac::ScopedMachSendRight server_task_port;
};
+using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals);
+
// Sets up the Mach communication ports with the server. Returns a set of
// globals that must live at least as long as the test.
scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
@@ -527,7 +537,7 @@ int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
while (listener.has_message()) {
LOG(INFO) << "Privileged process running callback.";
- callback(channel.get(), listener.get_first_message());
+ callback(channel.get(), listener.get_first_message(), globals.get());
LOG(INFO) << "Privileged process finishing callback.";
listener.pop_first_message();
}
@@ -556,7 +566,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
}
void SendSharedMemoryHandleCallback(IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
bool success = CheckContentsOfMessage1(message, kDataBuffer1);
SendControlMessage(sender, success);
}
@@ -582,7 +593,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
}
void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
std::string buffer(1 << 23, 'a');
bool success = CheckContentsOfMessage1(message, buffer);
SendControlMessage(sender, success);
@@ -610,7 +622,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
void SendTwoMessagesDifferentSharedMemoryHandleCallback(
IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
static int count = 0;
static bool success = true;
++count;
@@ -654,7 +667,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
void SendTwoMessagesSameSharedMemoryHandleCallback(
IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
static int count = 0;
static base::SharedMemoryHandle handle1;
++count;
@@ -701,7 +715,8 @@ TEST_F(IPCAttachmentBrokerMacTest,
void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
base::SharedMemoryHandle handle1;
base::SharedMemoryHandle handle2;
if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
@@ -745,7 +760,8 @@ TEST_F(IPCAttachmentBrokerMacTest,
void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
base::SharedMemoryHandle handle1;
base::SharedMemoryHandle handle2;
if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
@@ -802,7 +818,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
}
void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
TestSharedMemoryHandleMsg3::Schema::Param p;
if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
LOG(ERROR) << "Failed to deserialize message.";
@@ -883,7 +900,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
}
void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
- const IPC::Message&) {
+ const IPC::Message&,
+ ChildProcessGlobals* globals) {
// Do nothing special. The default behavior already runs the
// AttachmentBrokerPrivilegedMac.
}
@@ -937,7 +955,8 @@ TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
}
void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
bool success = CheckContentsOfMessage1(message, kDataBuffer1);
SendControlMessage(sender, success);
}
@@ -971,7 +990,9 @@ TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
CommonTearDown();
}
-void ShareToProcessCallback(IPC::Sender* sender, const IPC::Message& message) {
+void ShareToProcessCallback(IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
bool success = CheckContentsOfMessage1(message, kDataBuffer1);
SendControlMessage(sender, success);
}
@@ -1004,7 +1025,8 @@ TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
}
void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
- const IPC::Message& message) {
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
// Try to map the memory as writable.
@@ -1032,4 +1054,102 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
"ShareReadOnlyToProcess");
}
+// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
+// not have the task port for the parent process.
+TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (base::mac::IsOSSnowLeopard())
+ return;
+
+ SetBroker(new MockBroker);
+ CommonSetUp("SendSharedMemoryHandleToSelfDelayedPort");
+
+ // Technically, the channel is an endpoint, but we need the proxy listener to
+ // receive the messages so that it can quit the message loop.
+ channel()->SetAttachmentBrokerEndpoint(false);
+ get_proxy_listener()->set_listener(get_broker());
+
+ {
+ scoped_ptr<base::SharedMemory> shared_memory(
+ MakeSharedMemory(kDataBuffer1));
+ mach_port_urefs_t ref_count = IPC::GetMachRefCount(
+ shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
+
+ std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
+ const int kMessagesToTest = 3;
+ for (int i = 0; i < kMessagesToTest; ++i) {
+ base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
+ ids.push_back(
+ IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
+ IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
+ h.GetMemoryObject(), getpid(), ids[i]);
+ sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
+
+ // Send a dummy message, which will trigger the callback handler in the
+ // child process.
+ sender()->Send(new TestSharedMemoryHandleMsg4(1));
+ }
+
+ int received_message_count = 0;
+ while (received_message_count < kMessagesToTest) {
+ // Wait until the child process has sent this process a message.
+ base::MessageLoop::current()->Run();
+
+ // Wait for any asynchronous activity to complete.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ while (get_proxy_listener()->has_message()) {
+ get_proxy_listener()->pop_first_message();
+ received_message_count++;
+ }
+ }
+
+ for (int i = 0; i < kMessagesToTest; ++i) {
+ IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
+ ASSERT_TRUE(id);
+ scoped_refptr<IPC::BrokerableAttachment> received_attachment;
+ get_broker()->GetAttachmentWithId(*id, &received_attachment);
+ ASSERT_NE(received_attachment.get(), nullptr);
+
+ base::mac::ScopedMachSendRight memory_object(
+ GetMachPortFromBrokeredAttachment(received_attachment));
+ ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
+ }
+
+ // Check that the ref count hasn't changed.
+ EXPECT_EQ(ref_count,
+ IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
+ MACH_PORT_RIGHT_SEND));
+ }
+
+ FinalCleanUp();
+}
+
+void SendSharedMemoryHandleToSelfDelayedPortCallback(
+ IPC::Sender* sender,
+ const IPC::Message& message,
+ ChildProcessGlobals* globals) {
+ static int i = 0;
+ static base::ProcessId pid = message.get_sender_pid();
+ static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
+ ++i;
+
+ if (i == 1) {
+ // Pretend to not have the task port for the parent.
+ globals->port_provider.ClearPortMap();
+ } else if (i == 2) {
+ // Intentionally do nothing.
+ } else if (i == 3) {
+ // Setting the task port should trigger callbacks, eventually resulting in
+ // multiple attachment broker messages.
+ globals->port_provider.InsertEntry(pid, task_port);
+ }
+}
+
+MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
+ return CommonPrivilegedProcessMain(
+ &SendSharedMemoryHandleToSelfDelayedPortCallback,
+ "SendSharedMemoryHandleToSelfDelayedPort");
+}
+
} // namespace
diff --git a/ipc/attachment_broker_privileged.h b/ipc/attachment_broker_privileged.h
index 5520af2..5a55e67 100644
--- a/ipc/attachment_broker_privileged.h
+++ b/ipc/attachment_broker_privileged.h
@@ -71,12 +71,14 @@ class IPC_EXPORT AttachmentBrokerPrivileged : public IPC::AttachmentBroker {
ERROR_MAKE_RECEIVE_PORT = 6,
// Couldn't change the attributes of a Mach port.
ERROR_SET_ATTRIBUTES = 7,
- // Couldn't extract a right.
- ERROR_EXTRACT_RIGHT = 8,
+ // Couldn't extract a right from the destination.
+ ERROR_EXTRACT_DEST_RIGHT = 8,
// Couldn't send a Mach port in a call to mach_msg().
ERROR_SEND_MACH_PORT = 9,
// Couldn't decrease the ref count on a Mach port.
ERROR_DECREASE_REF = 10,
+ // Couldn't extract a right from the source.
+ ERROR_EXTRACT_SOURCE_RIGHT = 11,
ERROR_MAX
};
diff --git a/ipc/attachment_broker_privileged_mac.cc b/ipc/attachment_broker_privileged_mac.cc
index 8965eb5..16dbff4 100644
--- a/ipc/attachment_broker_privileged_mac.cc
+++ b/ipc/attachment_broker_privileged_mac.cc
@@ -55,9 +55,23 @@ namespace IPC {
AttachmentBrokerPrivilegedMac::AttachmentBrokerPrivilegedMac(
base::PortProvider* port_provider)
- : port_provider_(port_provider) {}
+ : port_provider_(port_provider) {
+ port_provider_->AddObserver(this);
+}
-AttachmentBrokerPrivilegedMac::~AttachmentBrokerPrivilegedMac() {}
+AttachmentBrokerPrivilegedMac::~AttachmentBrokerPrivilegedMac() {
+ port_provider_->RemoveObserver(this);
+ {
+ base::AutoLock l(precursors_lock_);
+ for (auto it : precursors_)
+ delete it.second;
+ }
+ {
+ base::AutoLock l(extractors_lock_);
+ for (auto it : extractors_)
+ delete it.second;
+ }
+}
bool AttachmentBrokerPrivilegedMac::SendAttachmentToProcess(
const scoped_refptr<IPC::BrokerableAttachment>& attachment,
@@ -68,25 +82,11 @@ bool AttachmentBrokerPrivilegedMac::SendAttachmentToProcess(
static_cast<internal::MachPortAttachmentMac*>(attachment.get());
MachPortWireFormat wire_format =
mach_port_attachment->GetWireFormat(destination_process);
-
- if (destination_process == base::Process::Current().Pid()) {
- RouteWireFormatToSelf(wire_format);
- mach_port_attachment->reset_mach_port_ownership();
- return true;
- }
-
- mach_port_name_t intermediate_port = CreateIntermediateMachPort(
- wire_format.destination_process,
- base::mac::ScopedMachSendRight(wire_format.mach_port));
+ AddPrecursor(wire_format.destination_process,
+ base::mac::ScopedMachSendRight(wire_format.mach_port),
+ wire_format.attachment_id);
mach_port_attachment->reset_mach_port_ownership();
- if (intermediate_port == MACH_PORT_NULL) {
- LogError(ERROR_MAKE_INTERMEDIATE);
- return false;
- }
-
- MachPortWireFormat intermediate_wire_format =
- CopyWireFormat(wire_format, intermediate_port);
- RouteWireFormatToAnother(intermediate_wire_format);
+ SendPrecursorsForProcess(wire_format.destination_process);
return true;
}
default:
@@ -106,8 +106,39 @@ bool AttachmentBrokerPrivilegedMac::OnMessageReceived(const Message& msg) {
return handled;
}
+void AttachmentBrokerPrivilegedMac::OnReceivedTaskPort(
+ base::ProcessHandle process) {
+ SendPrecursorsForProcess(process);
+}
+
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::AttachmentPrecursor(
+ const base::ProcessId& pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id)
+ : pid_(pid), port_(port.release()), id_(id) {}
+
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::~AttachmentPrecursor() {}
+
+base::mac::ScopedMachSendRight
+AttachmentBrokerPrivilegedMac::AttachmentPrecursor::TakePort() {
+ return base::mac::ScopedMachSendRight(port_.release());
+}
+
+AttachmentBrokerPrivilegedMac::AttachmentExtractor::AttachmentExtractor(
+ const base::ProcessId& source_pid,
+ const base::ProcessId& dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id)
+ : source_pid_(source_pid),
+ dest_pid_(dest_pid),
+ port_to_extract_(port),
+ id_(id) {}
+
+AttachmentBrokerPrivilegedMac::AttachmentExtractor::~AttachmentExtractor() {}
+
void AttachmentBrokerPrivilegedMac::OnDuplicateMachPort(
const IPC::Message& message) {
+ DCHECK_NE(0, message.get_sender_pid());
AttachmentBrokerMsg_DuplicateMachPort::Param param;
if (!AttachmentBrokerMsg_DuplicateMachPort::Read(&message, &param)) {
LogError(ERROR_PARSE_DUPLICATE_MACH_PORT_MESSAGE);
@@ -121,31 +152,18 @@ void AttachmentBrokerPrivilegedMac::OnDuplicateMachPort(
return;
}
- // Acquire a send right to the Mach port.
- base::ProcessId sender_pid = message.get_sender_pid();
- DCHECK_NE(sender_pid, base::GetCurrentProcId());
- base::mac::ScopedMachSendRight send_right(
- AcquireSendRight(sender_pid, wire_format.mach_port));
-
- if (wire_format.destination_process == base::GetCurrentProcId()) {
- // Intentionally leak the reference, as the consumer of the Chrome IPC
- // message will take ownership.
- mach_port_t final_mach_port = send_right.release();
- MachPortWireFormat final_wire_format(
- CopyWireFormat(wire_format, final_mach_port));
- RouteWireFormatToSelf(final_wire_format);
- return;
- }
-
- mach_port_name_t intermediate_mach_port = CreateIntermediateMachPort(
- wire_format.destination_process,
- base::mac::ScopedMachSendRight(send_right.release()));
- RouteWireFormatToAnother(CopyWireFormat(wire_format, intermediate_mach_port));
+ AddExtractor(message.get_sender_pid(), wire_format.destination_process,
+ wire_format.mach_port, wire_format.attachment_id);
+ ProcessExtractorsForProcess(message.get_sender_pid());
}
-void AttachmentBrokerPrivilegedMac::RouteWireFormatToSelf(
- const MachPortWireFormat& wire_format) {
- DCHECK_EQ(wire_format.destination_process, base::Process::Current().Pid());
+void AttachmentBrokerPrivilegedMac::RoutePrecursorToSelf(
+ AttachmentPrecursor* precursor) {
+ DCHECK_EQ(base::Process::Current().Pid(), precursor->pid());
+
+ // Intentionally leak the port, since the attachment takes ownership.
+ internal::MachPortAttachmentMac::WireFormat wire_format(
+ precursor->TakePort().release(), precursor->pid(), precursor->id());
scoped_refptr<BrokerableAttachment> attachment(
new internal::MachPortAttachmentMac(wire_format));
HandleReceivedAttachment(attachment);
@@ -173,19 +191,6 @@ void AttachmentBrokerPrivilegedMac::RouteWireFormatToAnother(
}
mach_port_name_t AttachmentBrokerPrivilegedMac::CreateIntermediateMachPort(
- base::ProcessId pid,
- base::mac::ScopedMachSendRight port_to_insert) {
- DCHECK_NE(pid, base::GetCurrentProcId());
- mach_port_t task_port = port_provider_->TaskForPid(pid);
- if (task_port == MACH_PORT_NULL) {
- LogError(ERROR_TASK_FOR_PID);
- return MACH_PORT_NULL;
- }
- return CreateIntermediateMachPort(
- task_port, base::mac::ScopedMachSendRight(port_to_insert.release()));
-}
-
-mach_port_name_t AttachmentBrokerPrivilegedMac::CreateIntermediateMachPort(
mach_port_t task_port,
base::mac::ScopedMachSendRight port_to_insert) {
DCHECK_NE(mach_task_self(), task_port);
@@ -219,7 +224,7 @@ mach_port_name_t AttachmentBrokerPrivilegedMac::CreateIntermediateMachPort(
mach_port_extract_right(task_port, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE,
&send_once_right, &send_right_type);
if (kr != KERN_SUCCESS) {
- LogError(ERROR_EXTRACT_RIGHT);
+ LogError(ERROR_EXTRACT_DEST_RIGHT);
mach_port_deallocate(task_port, endpoint);
return MACH_PORT_NULL;
}
@@ -263,8 +268,10 @@ base::mac::ScopedMachSendRight AttachmentBrokerPrivilegedMac::ExtractNamedRight(
kern_return_t kr =
mach_port_extract_right(task_port, named_right, MACH_MSG_TYPE_COPY_SEND,
&extracted_right, &extracted_right_type);
- if (kr != KERN_SUCCESS)
+ if (kr != KERN_SUCCESS) {
+ LogError(ERROR_EXTRACT_SOURCE_RIGHT);
return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
+ }
DCHECK_EQ(static_cast<mach_msg_type_name_t>(MACH_MSG_TYPE_PORT_SEND),
extracted_right_type);
@@ -288,4 +295,108 @@ AttachmentBrokerPrivilegedMac::CopyWireFormat(
wire_format.attachment_id);
}
+void AttachmentBrokerPrivilegedMac::SendPrecursorsForProcess(
+ base::ProcessId pid) {
+ base::AutoLock l(precursors_lock_);
+ auto it = precursors_.find(pid);
+ if (it == precursors_.end())
+ return;
+
+ // Whether this process is the destination process.
+ bool to_self = pid == base::GetCurrentProcId();
+
+ mach_port_t task_port = port_provider_->TaskForPid(pid);
+ if (!to_self && task_port == MACH_PORT_NULL)
+ return;
+
+ while (!it->second->empty()) {
+ auto precursor_it = it->second->begin();
+ if (to_self)
+ RoutePrecursorToSelf(*precursor_it);
+ else
+ SendPrecursor(*precursor_it, task_port);
+ it->second->erase(precursor_it);
+ }
+
+ delete it->second;
+ precursors_.erase(it);
+}
+
+void AttachmentBrokerPrivilegedMac::SendPrecursor(
+ AttachmentPrecursor* precursor,
+ mach_port_t task_port) {
+ DCHECK(task_port);
+ internal::MachPortAttachmentMac::WireFormat wire_format(
+ MACH_PORT_NULL, precursor->pid(), precursor->id());
+ base::mac::ScopedMachSendRight port_to_insert = precursor->TakePort();
+ mach_port_name_t intermediate_port = MACH_PORT_NULL;
+ if (port_to_insert.get() != MACH_PORT_NULL) {
+ intermediate_port = CreateIntermediateMachPort(
+ task_port, base::mac::ScopedMachSendRight(port_to_insert.release()));
+ }
+ RouteWireFormatToAnother(CopyWireFormat(wire_format, intermediate_port));
+}
+
+void AttachmentBrokerPrivilegedMac::AddPrecursor(
+ base::ProcessId pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id) {
+ base::AutoLock l(precursors_lock_);
+ auto it = precursors_.find(pid);
+ if (it == precursors_.end())
+ precursors_[pid] = new ScopedVector<AttachmentPrecursor>;
+
+ precursors_[pid]->push_back(new AttachmentPrecursor(
+ pid, base::mac::ScopedMachSendRight(port.release()), id));
+}
+
+void AttachmentBrokerPrivilegedMac::ProcessExtractorsForProcess(
+ base::ProcessId pid) {
+ base::AutoLock l(extractors_lock_);
+ auto it = extractors_.find(pid);
+ if (it == extractors_.end())
+ return;
+
+ mach_port_t task_port = port_provider_->TaskForPid(pid);
+ if (task_port == MACH_PORT_NULL)
+ return;
+
+ while (!it->second->empty()) {
+ auto extractor_it = it->second->begin();
+ ProcessExtractor(*extractor_it, task_port);
+ it->second->erase(extractor_it);
+ }
+
+ delete it->second;
+ extractors_.erase(it);
+}
+
+void AttachmentBrokerPrivilegedMac::ProcessExtractor(
+ AttachmentExtractor* extractor,
+ mach_port_t task_port) {
+ DCHECK(task_port);
+ base::mac::ScopedMachSendRight send_right =
+ ExtractNamedRight(task_port, extractor->port());
+ AddPrecursor(extractor->dest_pid(),
+ base::mac::ScopedMachSendRight(send_right.release()),
+ extractor->id());
+ SendPrecursorsForProcess(extractor->dest_pid());
+}
+
+void AttachmentBrokerPrivilegedMac::AddExtractor(
+ base::ProcessId source_pid,
+ base::ProcessId dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id) {
+ base::AutoLock l(extractors_lock_);
+ DCHECK_NE(base::GetCurrentProcId(), source_pid);
+
+ auto it = extractors_.find(source_pid);
+ if (it == extractors_.end())
+ extractors_[source_pid] = new ScopedVector<AttachmentExtractor>;
+
+ extractors_[source_pid]->push_back(
+ new AttachmentExtractor(source_pid, dest_pid, port, id));
+}
+
} // namespace IPC
diff --git a/ipc/attachment_broker_privileged_mac.h b/ipc/attachment_broker_privileged_mac.h
index e54d846..36abaf3 100644
--- a/ipc/attachment_broker_privileged_mac.h
+++ b/ipc/attachment_broker_privileged_mac.h
@@ -7,9 +7,14 @@
#include <mach/mach.h>
+#include <map>
+
#include "base/gtest_prod_util.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
#include "base/process/port_provider_mac.h"
+#include "base/synchronization/lock.h"
#include "ipc/attachment_broker_privileged.h"
#include "ipc/ipc_export.h"
#include "ipc/mach_port_attachment_mac.h"
@@ -49,7 +54,8 @@ namespace IPC {
// For the rest of this file, and the corresponding implementation file, R will
// be called the "intermediate Mach port" and M3 the "final Mach port".
class IPC_EXPORT AttachmentBrokerPrivilegedMac
- : public AttachmentBrokerPrivileged {
+ : public AttachmentBrokerPrivileged,
+ public base::PortProvider::Observer {
public:
explicit AttachmentBrokerPrivilegedMac(base::PortProvider* port_provider);
~AttachmentBrokerPrivilegedMac() override;
@@ -62,6 +68,9 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac
// IPC::Listener overrides.
bool OnMessageReceived(const Message& message) override;
+ // base::PortProvider::Observer override.
+ void OnReceivedTaskPort(base::ProcessHandle process) override;
+
private:
FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest,
InsertRight);
@@ -70,6 +79,58 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac
FRIEND_TEST_ALL_PREFIXES(AttachmentBrokerPrivilegedMacMultiProcessTest,
InsertTwoRights);
using MachPortWireFormat = internal::MachPortAttachmentMac::WireFormat;
+
+ // Contains all the information necessary to broker an attachment into a
+ // destination process. The only thing that prevents an AttachmentPrecusor
+ // from being immediately processed is if |port_provider_| does not yet have a
+ // task port for |pid|.
+ class IPC_EXPORT AttachmentPrecursor {
+ public:
+ AttachmentPrecursor(const base::ProcessId& pid,
+ base::mac::ScopedMachSendRight port_to_insert,
+ const BrokerableAttachment::AttachmentId& id);
+ ~AttachmentPrecursor();
+
+ // Caller takes ownership of |port_|.
+ base::mac::ScopedMachSendRight TakePort();
+
+ base::ProcessId pid() const { return pid_; }
+ const BrokerableAttachment::AttachmentId id() const { return id_; }
+
+ private:
+ // The pid of the destination process.
+ const base::ProcessId pid_;
+ // The final Mach port, as per definition at the top of this file.
+ base::mac::ScopedMachSendRight port_;
+ // The id of the attachment.
+ const BrokerableAttachment::AttachmentId id_;
+ DISALLOW_COPY_AND_ASSIGN(AttachmentPrecursor);
+ };
+
+ // Contains all the information necessary to extract a send right and create
+ // an AttachmentPrecursor. The only thing that prevents an AttachmentExtractor
+ // from being immediately processed is if |port_provider_| does not yet have a
+ // task port for |source_pid|.
+ class IPC_EXPORT AttachmentExtractor {
+ public:
+ AttachmentExtractor(const base::ProcessId& source_pid,
+ const base::ProcessId& dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id);
+ ~AttachmentExtractor();
+
+ base::ProcessId source_pid() const { return source_pid_; }
+ base::ProcessId dest_pid() const { return dest_pid_; }
+ mach_port_name_t port() const { return port_to_extract_; }
+ const BrokerableAttachment::AttachmentId id() const { return id_; }
+
+ private:
+ const base::ProcessId source_pid_;
+ const base::ProcessId dest_pid_;
+ mach_port_name_t port_to_extract_;
+ const BrokerableAttachment::AttachmentId id_;
+ };
+
// IPC message handlers.
void OnDuplicateMachPort(const Message& message);
@@ -78,20 +139,14 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac
MachPortWireFormat DuplicateMachPort(const MachPortWireFormat& wire_format,
base::ProcessId source_process);
- // |pid| must be another process.
+ // |task_port| is the task port of another process.
// |port_to_insert| must be a send right in the current task's name space.
// Creates an intermediate Mach port in |pid| and sends |port_to_insert| as a
// mach_msg to the intermediate Mach port.
- // On success, returns the name of the intermediate Mach port.
- // On failure, returns |MACH_PORT_NULL|.
+ // Returns the intermediate port on success, and MACH_PORT_NULL on failure.
// This method takes ownership of |port_to_insert|. On success, ownership is
// passed to the intermediate Mach port.
mach_port_name_t CreateIntermediateMachPort(
- base::ProcessId pid,
- base::mac::ScopedMachSendRight port_to_insert);
-
- // Same as the above method, where |task_port| is the task port of |pid|.
- mach_port_name_t CreateIntermediateMachPort(
mach_port_t task_port,
base::mac::ScopedMachSendRight port_to_insert);
@@ -115,7 +170,7 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac
// Consumes a reference to |wire_format.mach_port|, as ownership is implicitly
// passed to the consumer of the Chrome IPC message.
// Makes an attachment, queues it, and notifies the observers.
- void RouteWireFormatToSelf(const MachPortWireFormat& wire_format);
+ void RoutePrecursorToSelf(AttachmentPrecursor* precursor);
// |wire_format.destination_process| must be another process.
// |wire_format.mach_port| must be the intermediate Mach port.
@@ -123,8 +178,44 @@ class IPC_EXPORT AttachmentBrokerPrivilegedMac
// that receives the Chrome IPC message.
void RouteWireFormatToAnother(const MachPortWireFormat& wire_format);
+ // Atempts to broker all precursors whose destination is |pid|. Has no effect
+ // if |port_provider_| does not have the task port for |pid|.
+ void SendPrecursorsForProcess(base::ProcessId pid);
+
+ // Brokers a single precursor into the task represented by |task_port|.
+ void SendPrecursor(AttachmentPrecursor* precursor, mach_port_t task_port);
+
+ // Add a precursor to |precursors_|. Takes ownership of |port|.
+ void AddPrecursor(base::ProcessId pid,
+ base::mac::ScopedMachSendRight port,
+ const BrokerableAttachment::AttachmentId& id);
+
+ // Atempts to process all extractors whose source is |pid|. Has no effect
+ // if |port_provider_| does not have the task port for |pid|.
+ void ProcessExtractorsForProcess(base::ProcessId pid);
+
+ // Processes a single extractor whose source pid is represented by
+ // |task_port|.
+ void ProcessExtractor(AttachmentExtractor* extractor, mach_port_t task_port);
+
+ // Add an extractor to |extractors_|.
+ void AddExtractor(base::ProcessId source_pid,
+ base::ProcessId dest_pid,
+ mach_port_name_t port,
+ const BrokerableAttachment::AttachmentId& id);
+
// The port provider must live at least as long as the AttachmentBroker.
- const base::PortProvider* port_provider_;
+ base::PortProvider* port_provider_;
+
+ // For each ProcessId, a vector of precursors that are waiting to be
+ // sent.
+ std::map<base::ProcessId, ScopedVector<AttachmentPrecursor>*> precursors_;
+ base::Lock precursors_lock_;
+
+ // For each ProcessId, a vector of extractors that are waiting to be
+ // processed.
+ std::map<base::ProcessId, ScopedVector<AttachmentExtractor>*> extractors_;
+ base::Lock extractors_lock_;
DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMac);
};
diff --git a/ipc/attachment_broker_privileged_mac_unittest.cc b/ipc/attachment_broker_privileged_mac_unittest.cc
index 07222a3..3ad2a9d 100644
--- a/ipc/attachment_broker_privileged_mac_unittest.cc
+++ b/ipc/attachment_broker_privileged_mac_unittest.cc
@@ -119,6 +119,15 @@ scoped_ptr<base::SharedMemory> MapMemoryObject(mach_port_t memory_object,
return shared_memory;
}
+class MockPortProvider : public base::PortProvider {
+ public:
+ MockPortProvider() {}
+ ~MockPortProvider() override {}
+ mach_port_t TaskForPid(base::ProcessHandle process) const override {
+ return MACH_PORT_NULL;
+ }
+};
+
} // namespace
class AttachmentBrokerPrivilegedMacMultiProcessTest
@@ -159,6 +168,9 @@ class AttachmentBrokerPrivilegedMacMultiProcessTest
// Child process's task port.
base::mac::ScopedMachSendRight client_task_port_;
+ // Dummy port provider.
+ MockPortProvider port_provider_;
+
base::Process child_process_;
DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMacMultiProcessTest);
};
@@ -172,7 +184,7 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight) {
SetUpChild("InsertRightClient");
mach_msg_type_number_t original_name_count = GetActiveNameCount();
- IPC::AttachmentBrokerPrivilegedMac broker(nullptr);
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
// Create some shared memory.
scoped_ptr<base::SharedMemory> shared_memory =
@@ -239,7 +251,7 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice) {
SetUpChild("InsertSameRightTwiceClient");
mach_msg_type_number_t original_name_count = GetActiveNameCount();
- IPC::AttachmentBrokerPrivilegedMac broker(nullptr);
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
// Create some shared memory.
scoped_ptr<base::SharedMemory> shared_memory =
@@ -335,7 +347,7 @@ TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights) {
SetUpChild("InsertTwoRightsClient");
mach_msg_type_number_t original_name_count = GetActiveNameCount();
- IPC::AttachmentBrokerPrivilegedMac broker(nullptr);
+ IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
for (int i = 0; i < 2; ++i) {
// Create some shared memory.
diff --git a/ipc/ipc_channel_reader.cc b/ipc/ipc_channel_reader.cc
index f03f002..e1cdc47 100644
--- a/ipc/ipc_channel_reader.cc
+++ b/ipc/ipc_channel_reader.cc
@@ -163,7 +163,6 @@ bool ChannelReader::TranslateInputData(const char* input_data,
bool ChannelReader::HandleTranslatedMessage(
Message* translated_message,
const AttachmentIdVector& attachment_ids) {
-
// Immediately handle internal messages.
if (IsInternalMessage(*translated_message)) {
EmitLogBeforeDispatch(*translated_message);
diff --git a/ipc/ipc_test_messages.h b/ipc/ipc_test_messages.h
index d1247cb..62af913 100644
--- a/ipc/ipc_test_messages.h
+++ b/ipc/ipc_test_messages.h
@@ -31,4 +31,6 @@ IPC_MESSAGE_CONTROL4(TestSharedMemoryHandleMsg3,
base::SharedMemoryHandle,
base::FileDescriptor,
base::SharedMemoryHandle)
+IPC_MESSAGE_CONTROL1(TestSharedMemoryHandleMsg4, int)
+
#endif // defined(OS_MACOSX)