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 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 ~BlockDemuxer() override
{
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 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::Process child
= base::SpawnMultiProcessTestChild(
154 base::GetMultiProcessTestChildBaseCommandLine(),
155 base::LaunchOptions());
156 ASSERT_TRUE(child
.IsValid());
159 ASSERT_TRUE(child
.WaitForExit(&exit_code
));
160 EXPECT_EQ(0, exit_code
);
162 EXPECT_EQ(child
.Pid(), sender_pid
);
163 EXPECT_EQ(child
.Pid(), child_pid
);
164 EXPECT_EQ(sender_pid
, child_pid
);
167 MULTIPROCESS_TEST_MAIN(GetSenderPID
) {
168 CHECK(sandbox::InitializeXPC());
170 mach_port_t port
= MACH_PORT_NULL
;
171 CHECK_EQ(KERN_SUCCESS
, bootstrap_look_up(bootstrap_port
, kGetSenderPID
,
173 base::mac::ScopedMachSendRight
scoped_port(port
);
175 xpc_pipe_t pipe
= xpc_pipe_create_from_port(port
, 0);
177 xpc_object_t message
= xpc_dictionary_create(NULL
, NULL
, 0);
178 xpc_dictionary_set_int64(message
, "child_pid", getpid());
179 CHECK_EQ(0, xpc_pipe_simpleroutine(pipe
, message
));
181 xpc_release(message
);
187 XPC_TEST_F(ForwardMessage
) // {
189 XPCMessageServer
* first_server
= first
.server();
192 XPCMessageServer
* second_server
= second
.server();
194 ASSERT_TRUE(first
.Initialize(^(IPCMessage request
) {
195 xpc_dictionary_set_int64(request
.xpc
, "seen_by_first", 1);
196 first_server
->ForwardMessage(request
, second_server
->GetServerPort());
198 ASSERT_TRUE(second
.Initialize(^(IPCMessage request
) {
199 IPCMessage reply
= second_server
->CreateReply(request
);
200 xpc_dictionary_set_int64(reply
.xpc
, "seen_by_first",
201 xpc_dictionary_get_int64(request
.xpc
, "seen_by_first"));
202 xpc_dictionary_set_int64(reply
.xpc
, "seen_by_second", 2);
203 second_server
->SendReply(reply
);
206 xpc_object_t request
= xpc_dictionary_create(NULL
, NULL
, 0);
208 ASSERT_EQ(0, xpc_pipe_routine(first
.pipe(), request
, &reply
));
210 EXPECT_EQ(1, xpc_dictionary_get_int64(reply
, "seen_by_first"));
211 EXPECT_EQ(2, xpc_dictionary_get_int64(reply
, "seen_by_second"));
213 xpc_release(request
);
217 } // namespace sandbox