Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: ipc/attachment_broker_privileged_mac_unittest.cc

Issue 2473993003: Delete IPC::ChannelPosix, IPC::ChannelWin and IPC::AttachmentBroker. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/attachment_broker_privileged_mac.cc ('k') | ipc/attachment_broker_privileged_win.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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.
4
5 #include "ipc/attachment_broker_privileged_mac.h"
6
7 #include <mach/mach.h>
8 #include <mach/mach_vm.h>
9 #include <stddef.h>
10 #include <stdint.h>
11
12 #include <map>
13 #include <memory>
14
15 #include "base/command_line.h"
16 #include "base/mac/mac_util.h"
17 #include "base/mac/mach_logging.h"
18 #include "base/mac/mach_port_util.h"
19 #include "base/mac/scoped_mach_port.h"
20 #include "base/macros.h"
21 #include "base/memory/shared_memory.h"
22 #include "base/process/port_provider_mac.h"
23 #include "base/process/process_handle.h"
24 #include "base/sys_info.h"
25 #include "base/test/multiprocess_test.h"
26 #include "base/test/test_timeouts.h"
27 #include "ipc/test_util_mac.h"
28 #include "testing/multiprocess_func_list.h"
29
30 namespace IPC {
31
32 namespace {
33
34 static const std::string g_service_switch_name = "service_name";
35
36 // Sends a uint32_t to a mach port.
37 void SendUInt32(mach_port_t port, uint32_t message) {
38 int message_size = sizeof(uint32_t);
39 int total_size = message_size + sizeof(mach_msg_header_t);
40 void* buffer = malloc(total_size);
41 mach_msg_header_t* header = (mach_msg_header_t*)buffer;
42 header->msgh_remote_port = port;
43 header->msgh_local_port = MACH_PORT_NULL;
44 header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
45 header->msgh_reserved = 0;
46 header->msgh_id = 0;
47 header->msgh_size = total_size;
48 memcpy(static_cast<char*>(buffer) + sizeof(mach_msg_header_t), &message,
49 message_size);
50
51 kern_return_t kr;
52 kr = mach_msg(static_cast<mach_msg_header_t*>(buffer), MACH_SEND_MSG,
53 total_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
54 MACH_PORT_NULL);
55 MACH_CHECK(kr == KERN_SUCCESS, kr) << "SendUInt32";
56 free(buffer);
57 }
58
59 // Receives a uint32_t from a mach port.
60 uint32_t ReceiveUInt32(mach_port_t listening_port) {
61 int message_size = sizeof(uint32_t);
62 int total_size =
63 message_size + sizeof(mach_msg_header_t) + sizeof(mach_msg_trailer_t);
64 int options = MACH_RCV_MSG;
65 void* buffer = malloc(total_size);
66
67 int kr =
68 mach_msg(static_cast<mach_msg_header_t*>(buffer), options, 0, total_size,
69 listening_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
70 MACH_CHECK(kr == KERN_SUCCESS, kr) << "ReceiveUInt32";
71
72 uint32_t response;
73 memcpy(&response, static_cast<char*>(buffer) + sizeof(mach_msg_header_t),
74 message_size);
75
76 free(buffer);
77 return response;
78 }
79
80 // Sets up the mach communication ports with the server. Returns a port to which
81 // the server will send mach objects.
82 // |original_name_count| is an output variable that describes the number of
83 // active names in this task before the task port is shared with the server.
84 base::mac::ScopedMachReceiveRight CommonChildProcessSetUp(
85 mach_msg_type_number_t* original_name_count) {
86 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
87 std::string service_name =
88 cmd_line.GetSwitchValueASCII(g_service_switch_name);
89 base::mac::ScopedMachSendRight server_port(
90 LookupServer(service_name.c_str()));
91 base::mac::ScopedMachReceiveRight client_port(MakeReceivingPort());
92
93 // |server_port| is a newly allocated right which will be deallocated once
94 // this method returns.
95 *original_name_count = GetActiveNameCount() - 1;
96
97 // Send the port that this process is listening on to the server.
98 SendMachPort(server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
99
100 // Send the task port for this process.
101 SendMachPort(server_port.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
102 return client_port;
103 }
104
105 // Creates a new shared memory region populated with 'a'.
106 std::unique_ptr<base::SharedMemory> CreateAndPopulateSharedMemoryHandle(
107 size_t size) {
108 base::SharedMemoryHandle shm(size);
109 std::unique_ptr<base::SharedMemory> shared_memory(
110 new base::SharedMemory(shm, false));
111 shared_memory->Map(size);
112 memset(shared_memory->memory(), 'a', size);
113 return shared_memory;
114 }
115
116 // Create a shared memory region from a memory object. The returned object takes
117 // ownership of |memory_object|.
118 std::unique_ptr<base::SharedMemory> MapMemoryObject(mach_port_t memory_object,
119 size_t size) {
120 base::SharedMemoryHandle shm(memory_object, size, base::GetCurrentProcId());
121 std::unique_ptr<base::SharedMemory> shared_memory(
122 new base::SharedMemory(shm, false));
123 shared_memory->Map(size);
124 return shared_memory;
125 }
126
127 class MockPortProvider : public base::PortProvider {
128 public:
129 MockPortProvider() {}
130 ~MockPortProvider() override {}
131 mach_port_t TaskForPid(base::ProcessHandle process) const override {
132 return MACH_PORT_NULL;
133 }
134 };
135
136 } // namespace
137
138 class AttachmentBrokerPrivilegedMacMultiProcessTest
139 : public base::MultiProcessTest {
140 public:
141 AttachmentBrokerPrivilegedMacMultiProcessTest() {}
142
143 base::CommandLine MakeCmdLine(const std::string& procname) override {
144 base::CommandLine command_line = MultiProcessTest::MakeCmdLine(procname);
145 // Pass the service name to the child process.
146 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
147 return command_line;
148 }
149
150 void SetUpChild(const std::string& name) {
151 // Make a random service name so that this test doesn't conflict with other
152 // similar tests.
153 service_name_ = CreateRandomServiceName();
154 server_port_.reset(BecomeMachServer(service_name_.c_str()).release());
155 child_process_ = SpawnChild(name);
156 client_port_.reset(ReceiveMachPort(server_port_.get()).release());
157 client_task_port_.reset(ReceiveMachPort(server_port_.get()).release());
158 }
159
160 static const int s_memory_size = 99999;
161
162 protected:
163 std::string service_name_;
164
165 // A port on which the main process listens for mach messages from the child
166 // process.
167 base::mac::ScopedMachReceiveRight server_port_;
168
169 // A port on which the child process listens for mach messages from the main
170 // process.
171 base::mac::ScopedMachSendRight client_port_;
172
173 // Child process's task port.
174 base::mac::ScopedMachSendRight client_task_port_;
175
176 // Dummy port provider.
177 MockPortProvider port_provider_;
178
179 base::Process child_process_;
180 DISALLOW_COPY_AND_ASSIGN(AttachmentBrokerPrivilegedMacMultiProcessTest);
181 };
182
183 // The attachment broker inserts a right for a memory object into the
184 // destination task.
185 TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertRight) {
186 SetUpChild("InsertRightClient");
187 mach_msg_type_number_t original_name_count = GetActiveNameCount();
188 IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
189
190 // Create some shared memory.
191 std::unique_ptr<base::SharedMemory> shared_memory =
192 CreateAndPopulateSharedMemoryHandle(s_memory_size);
193 ASSERT_TRUE(shared_memory->handle().IsValid());
194
195 // Insert the memory object into the destination task, via an intermediate
196 // port.
197 IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
198 MACH_PORT_RIGHT_SEND);
199 mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort(
200 client_task_port_.get(),
201 base::mac::ScopedMachSendRight(shared_memory->handle().GetMemoryObject()),
202 nullptr);
203 EXPECT_NE(inserted_memory_object,
204 static_cast<mach_port_name_t>(MACH_PORT_NULL));
205 SendUInt32(client_port_.get(), inserted_memory_object);
206
207 // Check that no names have been leaked.
208 shared_memory.reset();
209 EXPECT_EQ(original_name_count, GetActiveNameCount());
210
211 int rv = -1;
212 ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
213 TestTimeouts::action_timeout(), &rv));
214 EXPECT_EQ(0, rv);
215 }
216
217 MULTIPROCESS_TEST_MAIN(InsertRightClient) {
218 mach_msg_type_number_t original_name_count = 0;
219 base::mac::ScopedMachReceiveRight client_port(
220 CommonChildProcessSetUp(&original_name_count).release());
221 base::mac::ScopedMachReceiveRight inserted_port(
222 ReceiveUInt32(client_port.get()));
223 base::mac::ScopedMachSendRight memory_object(
224 ReceiveMachPort(inserted_port.get()));
225 inserted_port.reset();
226
227 // The server should have inserted a right into this process.
228 EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
229
230 // Map the memory object and check its contents.
231 std::unique_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
232 memory_object.release(),
233 AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
234 const char* start = static_cast<const char*>(shared_memory->memory());
235 for (int i = 0;
236 i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
237 DCHECK_EQ(start[i], 'a');
238 }
239
240 // Check that no names have been leaked.
241 shared_memory.reset();
242 EXPECT_EQ(original_name_count, GetActiveNameCount());
243
244 return 0;
245 }
246
247 // The attachment broker inserts the right for a memory object into the
248 // destination task twice.
249 TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertSameRightTwice) {
250 SetUpChild("InsertSameRightTwiceClient");
251 mach_msg_type_number_t original_name_count = GetActiveNameCount();
252 IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
253
254 // Create some shared memory.
255 std::unique_ptr<base::SharedMemory> shared_memory =
256 CreateAndPopulateSharedMemoryHandle(s_memory_size);
257 ASSERT_TRUE(shared_memory->handle().IsValid());
258
259 // Insert the memory object into the destination task, via an intermediate
260 // port, twice.
261 for (int i = 0; i < 2; ++i) {
262 IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
263 MACH_PORT_RIGHT_SEND);
264 mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort(
265 client_task_port_.get(),
266 base::mac::ScopedMachSendRight(
267 shared_memory->handle().GetMemoryObject()),
268 nullptr);
269 EXPECT_NE(inserted_memory_object,
270 static_cast<mach_port_name_t>(MACH_PORT_NULL));
271 SendUInt32(client_port_.get(), inserted_memory_object);
272 }
273
274 // Check that no names have been leaked.
275 shared_memory.reset();
276 EXPECT_EQ(original_name_count, GetActiveNameCount());
277
278 int rv = -1;
279 ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
280 TestTimeouts::action_timeout(), &rv));
281 EXPECT_EQ(0, rv);
282 }
283
284 MULTIPROCESS_TEST_MAIN(InsertSameRightTwiceClient) {
285 mach_msg_type_number_t original_name_count = 0;
286 base::mac::ScopedMachReceiveRight client_port(
287 CommonChildProcessSetUp(&original_name_count).release());
288
289 // Receive two memory objects.
290 base::mac::ScopedMachReceiveRight inserted_port(
291 ReceiveUInt32(client_port.get()));
292 base::mac::ScopedMachReceiveRight inserted_port2(
293 ReceiveUInt32(client_port.get()));
294 base::mac::ScopedMachSendRight memory_object(
295 ReceiveMachPort(inserted_port.get()));
296 base::mac::ScopedMachSendRight memory_object2(
297 ReceiveMachPort(inserted_port2.get()));
298 inserted_port.reset();
299 inserted_port2.reset();
300
301 // Both rights are for the same Mach port, so only one new name should appear.
302 EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
303
304 // Map both memory objects and check their contents.
305 std::unique_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
306 memory_object.release(),
307 AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
308 char* start = static_cast<char*>(shared_memory->memory());
309 for (int i = 0;
310 i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
311 DCHECK_EQ(start[i], 'a');
312 }
313
314 std::unique_ptr<base::SharedMemory> shared_memory2(MapMemoryObject(
315 memory_object2.release(),
316 AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
317 char* start2 = static_cast<char*>(shared_memory2->memory());
318 for (int i = 0;
319 i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
320 DCHECK_EQ(start2[i], 'a');
321 }
322
323 // Check that the contents of both regions are shared.
324 start[0] = 'b';
325 DCHECK_EQ(start2[0], 'b');
326
327 // After releasing one shared memory region, the name count shouldn't change,
328 // since another reference exists.
329 shared_memory.reset();
330 EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
331
332 // After releasing the second shared memory region, the name count should be
333 // as if no names were ever inserted
334 shared_memory2.reset();
335 EXPECT_EQ(original_name_count, GetActiveNameCount());
336
337 return 0;
338 }
339
340 // The attachment broker inserts the rights for two memory objects into the
341 // destination task.
342 TEST_F(AttachmentBrokerPrivilegedMacMultiProcessTest, InsertTwoRights) {
343 SetUpChild("InsertTwoRightsClient");
344 mach_msg_type_number_t original_name_count = GetActiveNameCount();
345 IPC::AttachmentBrokerPrivilegedMac broker(&port_provider_);
346
347 for (int i = 0; i < 2; ++i) {
348 // Create some shared memory.
349 std::unique_ptr<base::SharedMemory> shared_memory =
350 CreateAndPopulateSharedMemoryHandle(s_memory_size);
351 ASSERT_TRUE(shared_memory->handle().IsValid());
352
353 // Insert the memory object into the destination task, via an intermediate
354 // port.
355 IncrementMachRefCount(shared_memory->handle().GetMemoryObject(),
356 MACH_PORT_RIGHT_SEND);
357 mach_port_name_t inserted_memory_object = base::CreateIntermediateMachPort(
358 client_task_port_.get(),
359 base::mac::ScopedMachSendRight(
360 shared_memory->handle().GetMemoryObject()),
361 nullptr);
362 EXPECT_NE(inserted_memory_object,
363 static_cast<mach_port_name_t>(MACH_PORT_NULL));
364 SendUInt32(client_port_.get(), inserted_memory_object);
365 }
366
367 // Check that no names have been leaked.
368 EXPECT_EQ(original_name_count, GetActiveNameCount());
369
370 int rv = -1;
371 ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
372 TestTimeouts::action_timeout(), &rv));
373 EXPECT_EQ(0, rv);
374 }
375
376 MULTIPROCESS_TEST_MAIN(InsertTwoRightsClient) {
377 mach_msg_type_number_t original_name_count = 0;
378 base::mac::ScopedMachReceiveRight client_port(
379 CommonChildProcessSetUp(&original_name_count).release());
380
381 // Receive two memory objects.
382 base::mac::ScopedMachReceiveRight inserted_port(
383 ReceiveUInt32(client_port.get()));
384 base::mac::ScopedMachReceiveRight inserted_port2(
385 ReceiveUInt32(client_port.get()));
386 base::mac::ScopedMachSendRight memory_object(
387 ReceiveMachPort(inserted_port.get()));
388 base::mac::ScopedMachSendRight memory_object2(
389 ReceiveMachPort(inserted_port2.get()));
390 inserted_port.reset();
391 inserted_port2.reset();
392
393 // There should be two new names to reflect the two new shared memory regions.
394 EXPECT_EQ(original_name_count + 2, GetActiveNameCount());
395
396 // Map both memory objects and check their contents.
397 std::unique_ptr<base::SharedMemory> shared_memory(MapMemoryObject(
398 memory_object.release(),
399 AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
400 char* start = static_cast<char*>(shared_memory->memory());
401 for (int i = 0;
402 i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
403 DCHECK_EQ(start[i], 'a');
404 }
405
406 std::unique_ptr<base::SharedMemory> shared_memory2(MapMemoryObject(
407 memory_object2.release(),
408 AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size));
409 char* start2 = static_cast<char*>(shared_memory2->memory());
410 for (int i = 0;
411 i < AttachmentBrokerPrivilegedMacMultiProcessTest::s_memory_size; ++i) {
412 DCHECK_EQ(start2[i], 'a');
413 }
414
415 // Check that the contents of both regions are not shared.
416 start[0] = 'b';
417 DCHECK_EQ(start2[0], 'a');
418
419 // After releasing one shared memory region, the name count should decrement.
420 shared_memory.reset();
421 EXPECT_EQ(original_name_count + 1, GetActiveNameCount());
422 shared_memory2.reset();
423 EXPECT_EQ(original_name_count, GetActiveNameCount());
424
425 return 0;
426 }
427
428 } // namespace IPC
OLDNEW
« no previous file with comments | « ipc/attachment_broker_privileged_mac.cc ('k') | ipc/attachment_broker_privileged_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698