1 // Copyright 2014 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.
5 #include "sandbox/mac/xpc_message_server.h"
9 #include <servers/bootstrap.h>
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/mac/mac_util.h"
14 #include "base/mac/scoped_mach_port.h"
15 #include "base/process/kill.h"
16 #include "base/test/multiprocess_test.h"
17 #include "sandbox/mac/xpc.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "testing/multiprocess_func_list.h"
23 class XPCMessageServerTest
: public testing::Test
{
25 virtual void SetUp() OVERRIDE
{
28 ASSERT_TRUE(InitializeXPC());
32 return base::mac::IsOSMountainLionOrLater();
36 // A MessageDemuxer that manages a test server and executes a block for every
38 class BlockDemuxer
: public MessageDemuxer
{
42 server_(this, MACH_PORT_NULL
),
46 virtual ~BlockDemuxer() {
50 Block_release(demux_block_
);
53 // Starts running the server, given a block to handle incoming IPC messages.
54 bool Initialize(void (^demux_block
)(IPCMessage request
)) {
55 if (!server_
.Initialize())
58 // Create a send right on the port so that the XPC pipe can be created.
59 if (mach_port_insert_right(mach_task_self(), server_
.GetServerPort(),
60 server_
.GetServerPort(), MACH_MSG_TYPE_MAKE_SEND
) != KERN_SUCCESS
) {
63 scoped_send_right_
.reset(server_
.GetServerPort());
65 demux_block_
= Block_copy(demux_block
);
66 pipe_
= xpc_pipe_create_from_port(server_
.GetServerPort(), 0);
71 virtual void DemuxMessage(IPCMessage request
) OVERRIDE
{
72 demux_block_(request
);
75 xpc_pipe_t
pipe() { return pipe_
; }
77 XPCMessageServer
* server() { return &server_
; }
80 void (^demux_block_
)(IPCMessage request
);
82 XPCMessageServer server_
;
84 base::mac::ScopedMachSendRight scoped_send_right_
;
89 #define XPC_TEST_F(name) TEST_F(XPCMessageServerTest, name) { \
93 XPC_TEST_F(ReceiveMessage) // {
95 XPCMessageServer
* server
= fixture
.server();
97 uint64_t __block value
= 0;
98 ASSERT_TRUE(fixture
.Initialize(^(IPCMessage request
) {
99 value
= xpc_dictionary_get_uint64(request
.xpc
, "test_value");
100 server
->SendReply(server
->CreateReply(request
));
103 xpc_object_t request
= xpc_dictionary_create(NULL
, NULL
, 0);
104 xpc_dictionary_set_uint64(request
, "test_value", 42);
107 EXPECT_EQ(0, xpc_pipe_routine(fixture
.pipe(), request
, &reply
));
109 EXPECT_EQ(42u, value
);
111 xpc_release(request
);
115 XPC_TEST_F(RejectMessage
) // {
116 BlockDemuxer fixture
;
117 XPCMessageServer
* server
= fixture
.server();
118 ASSERT_TRUE(fixture
.Initialize(^(IPCMessage request
) {
119 server
->RejectMessage(request
, EPERM
);
122 xpc_object_t request
= xpc_dictionary_create(NULL
, NULL
, 0);
124 EXPECT_EQ(0, xpc_pipe_routine(fixture
.pipe(), request
, &reply
));
126 EXPECT_EQ(EPERM
, xpc_dictionary_get_int64(reply
, "error"));
128 xpc_release(request
);
132 char kGetSenderPID
[] = "org.chromium.sandbox.test.GetSenderPID";
134 XPC_TEST_F(GetSenderPID
) // {
135 BlockDemuxer fixture
;
136 XPCMessageServer
* server
= fixture
.server();
138 pid_t __block sender_pid
= 0;
139 int64_t __block child_pid
= 0;
140 ASSERT_TRUE(fixture
.Initialize(^(IPCMessage request
) {
141 sender_pid
= server
->GetMessageSenderPID(request
);
142 child_pid
= xpc_dictionary_get_int64(request
.xpc
, "child_pid");
145 #pragma GCC diagnostic push
146 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
147 kern_return_t kr
= bootstrap_register(bootstrap_port
, kGetSenderPID
,
148 server
->GetServerPort());
149 #pragma GCC diagnostic pop
150 ASSERT_EQ(KERN_SUCCESS
, kr
);
152 base::ProcessHandle child_handle
= base::SpawnMultiProcessTestChild(
154 base::GetMultiProcessTestChildBaseCommandLine(),
155 base::LaunchOptions());
156 ASSERT_NE(base::kNullProcessHandle
, child_handle
);
159 ASSERT_TRUE(base::WaitForExitCode(child_handle
, &exit_code
));
160 EXPECT_EQ(0, exit_code
);
162 EXPECT_EQ(base::GetProcId(child_handle
), sender_pid
);
163 EXPECT_EQ(base::GetProcId(child_handle
), child_pid
);
164 EXPECT_EQ(sender_pid
, child_pid
);
166 base::CloseProcessHandle(child_handle
);
169 MULTIPROCESS_TEST_MAIN(GetSenderPID
) {
170 CHECK(sandbox::InitializeXPC());
172 mach_port_t port
= MACH_PORT_NULL
;
173 CHECK_EQ(KERN_SUCCESS
, bootstrap_look_up(bootstrap_port
, kGetSenderPID
,
175 base::mac::ScopedMachSendRight
scoped_port(port
);
177 xpc_pipe_t pipe
= xpc_pipe_create_from_port(port
, 0);
179 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
180 xpc_dictionary_set_int64(message
, "child_pid", getpid());
181 CHECK_EQ(0, xpc_pipe_simpleroutine(pipe
, message
));
183 xpc_release(message
);
189 XPC_TEST_F(ForwardMessage
) // {
191 XPCMessageServer
* first_server
= first
.server();
194 XPCMessageServer
* second_server
= second
.server();
196 ASSERT_TRUE(first
.Initialize(^(IPCMessage request
) {
197 xpc_dictionary_set_int64(request
.xpc
, "seen_by_first", 1);
198 first_server
->ForwardMessage(request
, second_server
->GetServerPort());
200 ASSERT_TRUE(second
.Initialize(^(IPCMessage request
) {
201 IPCMessage reply
= second_server
->CreateReply(request
);
202 xpc_dictionary_set_int64(reply
.xpc
, "seen_by_first",
203 xpc_dictionary_get_int64(request
.xpc
, "seen_by_first"));
204 xpc_dictionary_set_int64(reply
.xpc
, "seen_by_second", 2);
205 second_server
->SendReply(reply
);
208 xpc_object_t request
= xpc_dictionary_create(NULL
, NULL
, 0);
210 ASSERT_EQ(0, xpc_pipe_routine(first
.pipe(), request
, &reply
));
212 EXPECT_EQ(1, xpc_dictionary_get_int64(reply
, "seen_by_first"));
213 EXPECT_EQ(2, xpc_dictionary_get_int64(reply
, "seen_by_second"));
215 xpc_release(request
);
219 } // namespace sandbox