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

Side by Side Diff: ipc/attachment_broker_mac_unittest.cc

Issue 1397023002: ipc: Write end-to-end tests for SharedMemoryHandle brokering on Mac. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments from tsepez. Created 5 years, 2 months 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/BUILD.gn ('k') | ipc/ipc.gyp » ('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 "build/build_config.h"
6
7 #include <fcntl.h>
8 #include <sys/mman.h>
9
10 #include "base/command_line.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_file.h"
13 #include "base/files/scoped_temp_dir.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/shared_memory.h"
16 #include "ipc/attachment_broker_privileged_mac.h"
17 #include "ipc/attachment_broker_unprivileged_mac.h"
18 #include "ipc/ipc_listener.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_test_base.h"
21 #include "ipc/ipc_test_messages.h"
22 #include "ipc/test_util_mac.h"
23
24 namespace {
25
26 const char kDataBuffer1[] = "This is some test data to write to the file.";
27 const char kDataBuffer2[] = "The lazy dog and a fox.";
28 const char kDataBuffer3[] = "Two green bears but not a potato.";
29 const char kDataBuffer4[] = "Red potato is best potato.";
Tom Sepez 2015/10/12 15:52:21 Red potato is indeed best potato.
30 const std::string g_service_switch_name = "service_name";
31
32 enum TestResult {
33 RESULT_UNKNOWN,
34 RESULT_SUCCESS,
35 RESULT_FAILURE,
36 };
37
38 base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
39 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
40 if (attachment->GetType() !=
41 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
42 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
43 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
44 }
45
46 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
47 LOG(INFO) << "Brokerable type not MACH_PORT.";
48 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
49 }
50
51 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
52 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
53 return base::mac::ScopedMachSendRight(
54 received_mach_port_attachment->get_mach_port());
55 }
56
57 // Makes a Mach port backed SharedMemory region and fills it with |contents|.
58 scoped_ptr<base::SharedMemory> MakeSharedMemory(const std::string& contents) {
59 base::SharedMemoryHandle shm(contents.size());
60 if (!shm.IsValid()) {
61 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
62 return nullptr;
63 }
64 scoped_ptr<base::SharedMemory> shared_memory(
65 new base::SharedMemory(shm, false));
66 shared_memory->Map(contents.size());
67 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
68 return shared_memory;
69 }
70
71 // |message| must be deserializable as a TestSharedMemoryHandleMsg1.
72 base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
73 const IPC::Message& message) {
74 // Expect a message with a brokered attachment.
75 if (!message.HasBrokerableAttachments()) {
76 LOG(ERROR) << "Message missing brokerable attachment.";
77 return base::SharedMemoryHandle();
78 }
79
80 TestSharedMemoryHandleMsg1::Schema::Param p;
81 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
82 LOG(ERROR) << "Failed to deserialize message.";
83 return base::SharedMemoryHandle();
84 }
85
86 return base::get<1>(p);
87 }
88
89 // |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
90 // whether deserialization was successful. |handle1| and |handle2| are output
91 // variables populated on success.
92 bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
93 base::SharedMemoryHandle* handle1,
94 base::SharedMemoryHandle* handle2) {
95 // Expect a message with a brokered attachment.
96 if (!message.HasBrokerableAttachments()) {
97 LOG(ERROR) << "Message missing brokerable attachment.";
98 return false;
99 }
100
101 TestSharedMemoryHandleMsg2::Schema::Param p;
102 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
103 LOG(ERROR) << "Failed to deserialize message.";
104 return false;
105 }
106
107 *handle1 = base::get<0>(p);
108 *handle2 = base::get<1>(p);
109 return true;
110 }
111
112 // Returns |nullptr| on error.
113 scoped_ptr<base::SharedMemory> MapSharedMemoryHandle(
114 const base::SharedMemoryHandle& shm) {
115 if (!shm.IsValid()) {
116 LOG(ERROR) << "Invalid SharedMemoryHandle";
117 return nullptr;
118 }
119
120 size_t size;
121 if (!shm.GetSize(&size)) {
122 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
123 return nullptr;
124 }
125
126 scoped_ptr<base::SharedMemory> shared_memory(
127 new base::SharedMemory(shm, false));
128 shared_memory->Map(size);
129 return shared_memory;
130 }
131
132 // This method maps the SharedMemoryHandle, checks the contents, and then
133 // consumes a reference to the underlying Mach port.
134 bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
135 const std::string& contents) {
136 scoped_ptr<base::SharedMemory> shared_memory(MapSharedMemoryHandle(shm));
137
138 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
139 LOG(ERROR) << "Shared Memory contents not equivalent";
140 return false;
141 }
142 return true;
143 }
144
145 // This method mmaps the FileDescriptor, checks the contents, and then munmaps
146 // the FileDescriptor and closes the underlying fd.
147 bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
148 const std::string& contents) {
149 base::ScopedFD fd_closer(file_descriptor.fd);
150 lseek(file_descriptor.fd, 0, SEEK_SET);
151 scoped_ptr<char, base::FreeDeleter> buffer(
152 static_cast<char*>(malloc(contents.size())));
153 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
154 return false;
155
156 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
157 return result == 0;
158 }
159
160 // Open |fp| and populate it with |contents|.
161 base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
162 const std::string& contents) {
163 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
164 base::ScopedFD fd_closer(fd);
165 if (fd <= 0) {
166 LOG(ERROR) << "Error opening file at: " << fp.value();
167 return base::FileDescriptor();
168 }
169
170 if (lseek(fd, 0, SEEK_SET) != 0) {
171 LOG(ERROR) << "Error changing offset";
172 return base::FileDescriptor();
173 }
174
175 if (write(fd, contents.c_str(), contents.size()) !=
176 static_cast<ssize_t>(contents.size())) {
177 LOG(ERROR) << "Error writing to file";
178 return base::FileDescriptor();
179 }
180
181 return base::FileDescriptor(fd_closer.release(), true);
182 }
183
184 // Maps both handles, then checks that their contents matches |contents|. Then
185 // checks that changes to one are reflected in the other. Then consumes
186 // references to both underlying Mach ports.
187 bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
188 const base::SharedMemoryHandle& handle1,
189 const base::SharedMemoryHandle& handle2,
190 const std::string& contents) {
191 scoped_ptr<base::SharedMemory> shared_memory1(MapSharedMemoryHandle(handle1));
192 scoped_ptr<base::SharedMemory> shared_memory2(MapSharedMemoryHandle(handle2));
193
194 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
195 0) {
196 LOG(ERROR) << "Incorrect contents in shared_memory1";
197 return false;
198 }
199
200 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
201 contents.size()) != 0) {
202 LOG(ERROR) << "Incorrect contents in shared_memory2";
203 return false;
204 }
205
206 // Updating shared_memory1 should update shared_memory2.
207 const char known_string[] = "string bean";
208 if (shared_memory1->mapped_size() < strlen(known_string) ||
209 shared_memory2->mapped_size() < strlen(known_string)) {
210 LOG(ERROR) << "Shared memory size is too small";
211 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
Tom Sepez 2015/10/12 15:52:21 You'll want this memcpy to happen in the non-error
erikchen 2015/10/12 16:58:19 Whoops, done.
212 }
213
214 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
215 strlen(known_string)) != 0) {
216 LOG(ERROR) << "Incorrect contents in shared_memory2";
217 return false;
218 }
219
220 return true;
221 }
222
223 // |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
224 // whether the contents of the attached shared memory region matches |contents|.
225 // Consumes a reference to the underlying Mach port.
226 bool CheckContentsOfMessage1(const IPC::Message& message,
227 const std::string& contents) {
228 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
229 return CheckContentsOfSharedMemoryHandle(shm, contents);
230 }
231
232 // Once the test is finished, send a control message to the parent process with
233 // the result. The message may require the runloop to be run before its
234 // dispatched.
235 void SendControlMessage(IPC::Sender* sender, bool success) {
236 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
237 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
238 message->WriteInt(result);
239 sender->Send(message);
240 }
241
242 // Records the most recently received brokerable attachment's id.
243 class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
244 public:
245 void ReceivedBrokerableAttachmentWithId(
246 const IPC::BrokerableAttachment::AttachmentId& id) override {
247 id_ = id;
248 }
249 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
250
251 private:
252 IPC::BrokerableAttachment::AttachmentId id_;
253 };
254
255 // A broker which always sets the current process as the destination process
256 // for attachments.
257 class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
258 public:
259 MockBroker() {}
260 ~MockBroker() override {}
261 bool SendAttachmentToProcess(IPC::BrokerableAttachment* attachment,
262 base::ProcessId destination_process) override {
263 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
264 attachment, base::Process::Current().Pid());
265 }
266 };
267
268 // Forwards all messages to |listener_|. Quits the message loop after a
269 // message is received, or the channel has an error.
270 class ProxyListener : public IPC::Listener {
271 public:
272 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
273 ~ProxyListener() override {}
274
275 // The reason for exiting the message loop.
276 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
277
278 bool OnMessageReceived(const IPC::Message& message) override {
279 bool result = false;
280 if (listener_)
281 result = listener_->OnMessageReceived(message);
282 reason_ = MESSAGE_RECEIVED;
283 messages_.push_back(message);
284 base::MessageLoop::current()->QuitNow();
285 return result;
286 }
287
288 void OnChannelError() override {
289 reason_ = CHANNEL_ERROR;
290 base::MessageLoop::current()->QuitNow();
291 }
292
293 void set_listener(IPC::Listener* listener) { listener_ = listener; }
294 Reason get_reason() { return reason_; }
295 IPC::Message get_first_message() {
296 DCHECK(!messages_.empty());
297 return messages_[0];
298 }
299 void pop_first_message() {
300 DCHECK(!messages_.empty());
301 messages_.erase(messages_.begin());
302 }
303 bool has_message() { return !messages_.empty(); }
304
305 private:
306 IPC::Listener* listener_;
307 Reason reason_;
308 std::vector<IPC::Message> messages_;
309 };
310
311 // Waits for a result to be sent over the channel. Quits the message loop
312 // after a message is received, or the channel has an error.
313 class ResultListener : public IPC::Listener {
314 public:
315 ResultListener() : result_(RESULT_UNKNOWN) {}
316 ~ResultListener() override {}
317
318 bool OnMessageReceived(const IPC::Message& message) override {
319 base::PickleIterator iter(message);
320
321 int result;
322 EXPECT_TRUE(iter.ReadInt(&result));
323 result_ = static_cast<TestResult>(result);
324 return true;
325 }
326
327 TestResult get_result() { return result_; }
328
329 private:
330 TestResult result_;
331 };
332
333 class MockPortProvider : public base::PortProvider {
334 public:
335 mach_port_t TaskForPid(base::ProcessHandle process) const override {
336 auto it = port_map_.find(process);
337 if (it != port_map_.end())
338 return it->second;
339 return MACH_PORT_NULL;
340 }
341
342 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
343 port_map_[process] = task_port;
344 }
345
346 private:
347 std::map<base::ProcessHandle, mach_port_t> port_map_;
348 };
349
350 // End-to-end tests for the attachment brokering process on Mac.
351 // The parent process acts as an unprivileged process. The child process acts
352 // as the privileged process.
353 class IPCAttachmentBrokerMacTest : public IPCTestBase {
354 public:
355 IPCAttachmentBrokerMacTest() {}
356 ~IPCAttachmentBrokerMacTest() override {}
357
358 base::CommandLine MakeCmdLine(const std::string& procname) override {
359 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
360 // Pass the service name to the child process.
361 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
362 return command_line;
363 }
364
365 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
366 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
367 broker_.reset(broker);
368 }
369
370 // Setup shared between tests.
371 void CommonSetUp(const char* name) {
372 Init(name);
373 service_name_ = IPC::CreateRandomServiceName();
374 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
375
376 if (!broker_.get())
377 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
378
379 broker_->AddObserver(&observer_);
380 CreateChannel(&proxy_listener_);
381 broker_->DesignateBrokerCommunicationChannel(channel());
382 ASSERT_TRUE(ConnectChannel());
383 ASSERT_TRUE(StartClient());
384
385 client_port_.reset(IPC::ReceiveMachPort(server_port_).release());
386 IPC::SendMachPort(client_port_, mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
387 active_names_at_start_ = IPC::GetActiveNameCount();
388 get_proxy_listener()->set_listener(&result_listener_);
389 }
390
391 void CheckChildResult() {
392 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
393 get_proxy_listener()->get_reason());
394 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
395 }
396
397 void FinalCleanUp() {
398 // There should be no leaked names.
399 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
400
401 // Close the channel so the client's OnChannelError() gets fired.
402 channel()->Close();
403
404 EXPECT_TRUE(WaitForClientShutdown());
405 DestroyChannel();
406 broker_.reset();
407 }
408
409 // Teardown shared between most tests.
410 void CommonTearDown() {
411 CheckChildResult();
412 FinalCleanUp();
413 }
414
415 // Makes a SharedMemory region, fills it with |contents|, sends the handle
416 // over Chrome IPC, and unmaps the region.
417 void SendMessage1(const std::string& contents) {
418 scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
419 IPC::Message* message =
420 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
421 sender()->Send(message);
422 }
423
424 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
425 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
426 AttachmentBrokerObserver* get_observer() { return &observer_; }
427 ResultListener* get_result_listener() { return &result_listener_; }
428
429 private:
430 ProxyListener proxy_listener_;
431 scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
432 AttachmentBrokerObserver observer_;
433
434 // A port on which the main process listens for mach messages from the child
435 // process.
436 base::mac::ScopedMachReceiveRight server_port_;
437
438 // A port on which the child process listens for mach messages from the main
439 // process.
440 base::mac::ScopedMachSendRight client_port_;
441
442 // The number of active names immediately after set up.
443 mach_msg_type_number_t active_names_at_start_;
444
445 std::string service_name_;
446
447 ResultListener result_listener_;
448 };
449
450 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
451 const IPC::Message& message);
452
453 // These objects are globally accessible, and are expected to outlive all IPC
454 // Channels.
455 struct ChildProcessGlobals {
456 IPC::AttachmentBrokerPrivilegedMac broker;
457 MockPortProvider port_provider;
458 base::mac::ScopedMachSendRight server_task_port;
459 };
460
461 // Sets up the Mach communication ports with the server. Returns a set of
462 // globals that must live at least as long as the test.
463 scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
464 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
465 std::string service_name =
466 cmd_line.GetSwitchValueASCII(g_service_switch_name);
467 base::mac::ScopedMachSendRight server_port(
468 IPC::LookupServer(service_name.c_str()));
469 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
470
471 // Send the port that this process is listening on to the server.
472 IPC::SendMachPort(server_port, client_port, MACH_MSG_TYPE_MAKE_SEND);
473
474 // Receive the task port of the server process.
475 base::mac::ScopedMachSendRight server_task_port(
476 IPC::ReceiveMachPort(client_port));
477
478 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
479 globals->port_provider.InsertEntry(getppid(), server_task_port);
480 globals->broker.SetPortProvider(&globals->port_provider);
481 globals->server_task_port.reset(server_task_port.release());
482 return globals;
483 }
484
485 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
486 const char* channel_name) {
487 LOG(INFO) << "Privileged process start.";
488 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
489
490 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
491
492 base::MessageLoopForIO main_message_loop;
493 ProxyListener listener;
494
495 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
496 IPCTestBase::GetChannelName(channel_name), &listener));
497 globals->broker.RegisterCommunicationChannel(channel.get());
498 CHECK(channel->Connect());
499
500 while (true) {
501 LOG(INFO) << "Privileged process spinning run loop.";
502 base::MessageLoop::current()->Run();
503 ProxyListener::Reason reason = listener.get_reason();
504 if (reason == ProxyListener::CHANNEL_ERROR)
505 break;
506
507 while (listener.has_message()) {
508 LOG(INFO) << "Privileged process running callback.";
509 callback(channel.get(), listener.get_first_message());
510 LOG(INFO) << "Privileged process finishing callback.";
511 listener.pop_first_message();
512 }
513 }
514
515 if (active_names_at_start != IPC::GetActiveNameCount()) {
516 LOG(INFO) << "Memory leak!.";
517 }
518 LOG(INFO) << "Privileged process end.";
519 return 0;
520 }
521
522 // An unprivileged process makes a shared memory region, and writes a string to
523 // it. The SharedMemoryHandle is sent to the privileged process using Chrome
524 // IPC. The privileged process checks that it received the same memory region.
525 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
526 CommonSetUp("SendSharedMemoryHandle");
527
528 SendMessage1(kDataBuffer1);
529 base::MessageLoop::current()->Run();
530 CommonTearDown();
531 }
532
533 void SendSharedMemoryHandleCallback(IPC::Sender* sender,
534 const IPC::Message& message) {
535 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
536 SendControlMessage(sender, success);
537 }
538
539 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
540 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
541 "SendSharedMemoryHandle");
542 }
543
544 // Similar to SendSharedMemoryHandle, but sends a very long shared memory
545 // region.
546 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
547 CommonSetUp("SendSharedMemoryHandleLong");
548
549 std::string buffer(1 << 23, 'a');
550 SendMessage1(buffer);
551 base::MessageLoop::current()->Run();
552 CommonTearDown();
553 }
554
555 void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
556 const IPC::Message& message) {
557 std::string buffer(1 << 23, 'a');
558 bool success = CheckContentsOfMessage1(message, buffer);
559 SendControlMessage(sender, success);
560 }
561
562 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
563 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
564 "SendSharedMemoryHandleLong");
565 }
566
567 // Similar to SendSharedMemoryHandle, but sends two different shared memory
568 // regions in two messages.
569 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
570 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
571
572 SendMessage1(kDataBuffer1);
573 SendMessage1(kDataBuffer2);
574 base::MessageLoop::current()->Run();
575 CommonTearDown();
576 }
577
578 void SendTwoMessagesDifferentSharedMemoryHandleCallback(
579 IPC::Sender* sender,
580 const IPC::Message& message) {
581 static int count = 0;
582 static bool success = true;
583 ++count;
584 if (count == 1) {
585 success &= CheckContentsOfMessage1(message, kDataBuffer1);
586 } else if (count == 2) {
587 success &= CheckContentsOfMessage1(message, kDataBuffer2);
588 SendControlMessage(sender, success);
589 }
590 }
591
592 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
593 return CommonPrivilegedProcessMain(
594 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
595 "SendTwoMessagesDifferentSharedMemoryHandle");
596 }
597
598 // Similar to SendSharedMemoryHandle, but sends the same shared memory region in
599 // two messages.
600 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
601 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
602
603 {
604 scoped_ptr<base::SharedMemory> shared_memory(
605 MakeSharedMemory(kDataBuffer1));
606
607 for (int i = 0; i < 2; ++i) {
608 IPC::Message* message =
609 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
610 sender()->Send(message);
611 }
612 }
613
614 base::MessageLoop::current()->Run();
615 CommonTearDown();
616 }
617
618 void SendTwoMessagesSameSharedMemoryHandleCallback(
619 IPC::Sender* sender,
620 const IPC::Message& message) {
621 static int count = 0;
622 static base::SharedMemoryHandle handle1;
623 ++count;
624
625 if (count == 1) {
626 handle1 = GetSharedMemoryHandleFromMsg1(message);
627 } else if (count == 2) {
628 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
629
630 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
631 handle1, handle2, kDataBuffer1);
632 SendControlMessage(sender, success);
633 }
634 }
635
636 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
637 return CommonPrivilegedProcessMain(
638 &SendTwoMessagesSameSharedMemoryHandleCallback,
639 "SendTwoMessagesSameSharedMemoryHandle");
640 }
641
642 // Similar to SendSharedMemoryHandle, but sends one message with two different
643 // memory regions.
644 TEST_F(IPCAttachmentBrokerMacTest,
645 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
646 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
647
648 {
649 scoped_ptr<base::SharedMemory> shared_memory1(
650 MakeSharedMemory(kDataBuffer1));
651 scoped_ptr<base::SharedMemory> shared_memory2(
652 MakeSharedMemory(kDataBuffer2));
653 IPC::Message* message = new TestSharedMemoryHandleMsg2(
654 shared_memory1->handle(), shared_memory2->handle());
655 sender()->Send(message);
656 }
657 base::MessageLoop::current()->Run();
658 CommonTearDown();
659 }
660
661 void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
662 IPC::Sender* sender,
663 const IPC::Message& message) {
664 base::SharedMemoryHandle handle1;
665 base::SharedMemoryHandle handle2;
666 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
667 LOG(ERROR) << "Failed to deserialize message.";
668 SendControlMessage(sender, false);
669 return;
670 }
671
672 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
673 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
674 SendControlMessage(sender, success);
675 }
676
677 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
678 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
679 return CommonPrivilegedProcessMain(
680 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
681 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
682 }
683
684 // Similar to SendSharedMemoryHandle, but sends one message that contains the
685 // same memory region twice.
686 TEST_F(IPCAttachmentBrokerMacTest,
687 SendOneMessageWithTwoSameSharedMemoryHandles) {
688 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
689
690 {
691 scoped_ptr<base::SharedMemory> shared_memory(
692 MakeSharedMemory(kDataBuffer1));
693 IPC::Message* message = new TestSharedMemoryHandleMsg2(
694 shared_memory->handle(), shared_memory->handle());
695 sender()->Send(message);
696 }
697 base::MessageLoop::current()->Run();
698 CommonTearDown();
699 }
700
701 void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
702 IPC::Sender* sender,
703 const IPC::Message& message) {
704 base::SharedMemoryHandle handle1;
705 base::SharedMemoryHandle handle2;
706 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
707 LOG(ERROR) << "Failed to deserialize message.";
708 SendControlMessage(sender, false);
709 return;
710 }
711
712 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
713 handle1, handle2, kDataBuffer1);
714 SendControlMessage(sender, success);
715 }
716
717 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
718 SendOneMessageWithTwoSameSharedMemoryHandles) {
719 return CommonPrivilegedProcessMain(
720 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
721 "SendOneMessageWithTwoSameSharedMemoryHandles");
722 }
723
724 // Sends one message with two Posix FDs and two Mach ports.
725 TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
726 base::ScopedTempDir temp_dir;
727 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
728 base::FilePath fp1, fp2;
729 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
730 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
731
732 CommonSetUp("SendPosixFDAndMachPort");
733
734 {
735 scoped_ptr<base::SharedMemory> shared_memory1(
736 MakeSharedMemory(kDataBuffer1));
737 scoped_ptr<base::SharedMemory> shared_memory2(
738 MakeSharedMemory(kDataBuffer2));
739
740 base::FileDescriptor file_descriptor1(
741 MakeFileDescriptor(fp1, kDataBuffer3));
742 base::FileDescriptor file_descriptor2(
743 MakeFileDescriptor(fp2, kDataBuffer4));
744
745 IPC::Message* message = new TestSharedMemoryHandleMsg3(
746 file_descriptor1, shared_memory1->handle(), file_descriptor2,
747 shared_memory2->handle());
748 sender()->Send(message);
749 }
750
751 base::MessageLoop::current()->Run();
752 CommonTearDown();
753 }
754
755 void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
756 const IPC::Message& message) {
757 TestSharedMemoryHandleMsg3::Schema::Param p;
758 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
759 LOG(ERROR) << "Failed to deserialize message.";
760 SendControlMessage(sender, false);
761 return;
762 }
763
764 base::SharedMemoryHandle handle1 = base::get<1>(p);
765 base::SharedMemoryHandle handle2 = base::get<3>(p);
766 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
767 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
768 if (!success1)
769 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
770
771 bool success2 =
772 CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
773 CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
774 if (!success2)
775 LOG(ERROR) << "FileDescriptors have wrong contents.";
776
777 SendControlMessage(sender, success1 && success2);
778 }
779
780 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
781 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
782 "SendPosixFDAndMachPort");
783 }
784
785 // Similar to SendHandle, except the attachment's destination process is this
786 // process. This is an unrealistic scenario, but simulates an unprivileged
787 // process sending an attachment to another unprivileged process.
788 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
789 SetBroker(new MockBroker);
790 CommonSetUp("SendSharedMemoryHandleToSelf");
791
792 // Technically, the channel is an endpoint, but we need the proxy listener to
793 // receive the messages so that it can quit the message loop.
794 channel()->SetAttachmentBrokerEndpoint(false);
795 get_proxy_listener()->set_listener(get_broker());
796
797 {
798 scoped_ptr<base::SharedMemory> shared_memory(
799 MakeSharedMemory(kDataBuffer1));
800 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
801 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
802
803 IPC::Message* message =
804 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
805 sender()->Send(message);
806 base::MessageLoop::current()->Run();
807
808 // Get the received attachment.
809 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
810 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
811 get_broker()->GetAttachmentWithId(*id, &received_attachment);
812 ASSERT_NE(received_attachment.get(), nullptr);
813
814 // Check that it's has the same name, but that the ref count has increased.
815 base::mac::ScopedMachSendRight memory_object(
816 GetMachPortFromBrokeredAttachment(received_attachment));
817 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
818 EXPECT_EQ(ref_count + 1,
819 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
820 MACH_PORT_RIGHT_SEND));
821 }
822
823 FinalCleanUp();
824 }
825
826 void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
827 const IPC::Message&) {
828 // Do nothing special. The default behavior already runs the
829 // AttachmentBrokerPrivilegedMac.
830 }
831
832 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
833 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
834 "SendSharedMemoryHandleToSelf");
835 }
836
837 } // namespace
OLDNEW
« no previous file with comments | « ipc/BUILD.gn ('k') | ipc/ipc.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698