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

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: More Win compile errors. 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/attachment_broker_privileged_win_unittest.cc » ('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.";
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 return false;
212 }
213 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
214
215 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
216 strlen(known_string)) != 0) {
217 LOG(ERROR) << "Incorrect contents in shared_memory2";
218 return false;
219 }
220
221 return true;
222 }
223
224 // |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
225 // whether the contents of the attached shared memory region matches |contents|.
226 // Consumes a reference to the underlying Mach port.
227 bool CheckContentsOfMessage1(const IPC::Message& message,
228 const std::string& contents) {
229 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
230 return CheckContentsOfSharedMemoryHandle(shm, contents);
231 }
232
233 // Once the test is finished, send a control message to the parent process with
234 // the result. The message may require the runloop to be run before its
235 // dispatched.
236 void SendControlMessage(IPC::Sender* sender, bool success) {
237 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
238 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
239 message->WriteInt(result);
240 sender->Send(message);
241 }
242
243 // Records the most recently received brokerable attachment's id.
244 class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
245 public:
246 void ReceivedBrokerableAttachmentWithId(
247 const IPC::BrokerableAttachment::AttachmentId& id) override {
248 id_ = id;
249 }
250 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
251
252 private:
253 IPC::BrokerableAttachment::AttachmentId id_;
254 };
255
256 // A broker which always sets the current process as the destination process
257 // for attachments.
258 class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
259 public:
260 MockBroker() {}
261 ~MockBroker() override {}
262 bool SendAttachmentToProcess(IPC::BrokerableAttachment* attachment,
263 base::ProcessId destination_process) override {
264 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
265 attachment, base::Process::Current().Pid());
266 }
267 };
268
269 // Forwards all messages to |listener_|. Quits the message loop after a
270 // message is received, or the channel has an error.
271 class ProxyListener : public IPC::Listener {
272 public:
273 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
274 ~ProxyListener() override {}
275
276 // The reason for exiting the message loop.
277 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
278
279 bool OnMessageReceived(const IPC::Message& message) override {
280 bool result = false;
281 if (listener_)
282 result = listener_->OnMessageReceived(message);
283 reason_ = MESSAGE_RECEIVED;
284 messages_.push_back(message);
285 base::MessageLoop::current()->QuitNow();
286 return result;
287 }
288
289 void OnChannelError() override {
290 reason_ = CHANNEL_ERROR;
291 base::MessageLoop::current()->QuitNow();
292 }
293
294 void set_listener(IPC::Listener* listener) { listener_ = listener; }
295 Reason get_reason() { return reason_; }
296 IPC::Message get_first_message() {
297 DCHECK(!messages_.empty());
298 return messages_[0];
299 }
300 void pop_first_message() {
301 DCHECK(!messages_.empty());
302 messages_.erase(messages_.begin());
303 }
304 bool has_message() { return !messages_.empty(); }
305
306 private:
307 IPC::Listener* listener_;
308 Reason reason_;
309 std::vector<IPC::Message> messages_;
310 };
311
312 // Waits for a result to be sent over the channel. Quits the message loop
313 // after a message is received, or the channel has an error.
314 class ResultListener : public IPC::Listener {
315 public:
316 ResultListener() : result_(RESULT_UNKNOWN) {}
317 ~ResultListener() override {}
318
319 bool OnMessageReceived(const IPC::Message& message) override {
320 base::PickleIterator iter(message);
321
322 int result;
323 EXPECT_TRUE(iter.ReadInt(&result));
324 result_ = static_cast<TestResult>(result);
325 return true;
326 }
327
328 TestResult get_result() { return result_; }
329
330 private:
331 TestResult result_;
332 };
333
334 class MockPortProvider : public base::PortProvider {
335 public:
336 mach_port_t TaskForPid(base::ProcessHandle process) const override {
337 auto it = port_map_.find(process);
338 if (it != port_map_.end())
339 return it->second;
340 return MACH_PORT_NULL;
341 }
342
343 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
344 port_map_[process] = task_port;
345 }
346
347 private:
348 std::map<base::ProcessHandle, mach_port_t> port_map_;
349 };
350
351 // End-to-end tests for the attachment brokering process on Mac.
352 // The parent process acts as an unprivileged process. The child process acts
353 // as the privileged process.
354 class IPCAttachmentBrokerMacTest : public IPCTestBase {
355 public:
356 IPCAttachmentBrokerMacTest() {}
357 ~IPCAttachmentBrokerMacTest() override {}
358
359 base::CommandLine MakeCmdLine(const std::string& procname) override {
360 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
361 // Pass the service name to the child process.
362 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
363 return command_line;
364 }
365
366 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
367 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
368 broker_.reset(broker);
369 }
370
371 // Setup shared between tests.
372 void CommonSetUp(const char* name) {
373 Init(name);
374 service_name_ = IPC::CreateRandomServiceName();
375 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
376
377 if (!broker_.get())
378 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
379
380 broker_->AddObserver(&observer_);
381 CreateChannel(&proxy_listener_);
382 broker_->DesignateBrokerCommunicationChannel(channel());
383 ASSERT_TRUE(ConnectChannel());
384 ASSERT_TRUE(StartClient());
385
386 client_port_.reset(IPC::ReceiveMachPort(server_port_).release());
387 IPC::SendMachPort(client_port_, mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
388 active_names_at_start_ = IPC::GetActiveNameCount();
389 get_proxy_listener()->set_listener(&result_listener_);
390 }
391
392 void CheckChildResult() {
393 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
394 get_proxy_listener()->get_reason());
395 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
396 }
397
398 void FinalCleanUp() {
399 // There should be no leaked names.
400 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
401
402 // Close the channel so the client's OnChannelError() gets fired.
403 channel()->Close();
404
405 EXPECT_TRUE(WaitForClientShutdown());
406 DestroyChannel();
407 broker_.reset();
408 }
409
410 // Teardown shared between most tests.
411 void CommonTearDown() {
412 CheckChildResult();
413 FinalCleanUp();
414 }
415
416 // Makes a SharedMemory region, fills it with |contents|, sends the handle
417 // over Chrome IPC, and unmaps the region.
418 void SendMessage1(const std::string& contents) {
419 scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
420 IPC::Message* message =
421 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
422 sender()->Send(message);
423 }
424
425 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
426 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
427 AttachmentBrokerObserver* get_observer() { return &observer_; }
428 ResultListener* get_result_listener() { return &result_listener_; }
429
430 private:
431 ProxyListener proxy_listener_;
432 scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
433 AttachmentBrokerObserver observer_;
434
435 // A port on which the main process listens for mach messages from the child
436 // process.
437 base::mac::ScopedMachReceiveRight server_port_;
438
439 // A port on which the child process listens for mach messages from the main
440 // process.
441 base::mac::ScopedMachSendRight client_port_;
442
443 // The number of active names immediately after set up.
444 mach_msg_type_number_t active_names_at_start_;
445
446 std::string service_name_;
447
448 ResultListener result_listener_;
449 };
450
451 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
452 const IPC::Message& message);
453
454 // These objects are globally accessible, and are expected to outlive all IPC
455 // Channels.
456 struct ChildProcessGlobals {
457 IPC::AttachmentBrokerPrivilegedMac broker;
458 MockPortProvider port_provider;
459 base::mac::ScopedMachSendRight server_task_port;
460 };
461
462 // Sets up the Mach communication ports with the server. Returns a set of
463 // globals that must live at least as long as the test.
464 scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
465 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
466 std::string service_name =
467 cmd_line.GetSwitchValueASCII(g_service_switch_name);
468 base::mac::ScopedMachSendRight server_port(
469 IPC::LookupServer(service_name.c_str()));
470 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
471
472 // Send the port that this process is listening on to the server.
473 IPC::SendMachPort(server_port, client_port, MACH_MSG_TYPE_MAKE_SEND);
474
475 // Receive the task port of the server process.
476 base::mac::ScopedMachSendRight server_task_port(
477 IPC::ReceiveMachPort(client_port));
478
479 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
480 globals->port_provider.InsertEntry(getppid(), server_task_port);
481 globals->broker.SetPortProvider(&globals->port_provider);
482 globals->server_task_port.reset(server_task_port.release());
483 return globals;
484 }
485
486 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
487 const char* channel_name) {
488 LOG(INFO) << "Privileged process start.";
489 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
490
491 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
492
493 base::MessageLoopForIO main_message_loop;
494 ProxyListener listener;
495
496 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
497 IPCTestBase::GetChannelName(channel_name), &listener));
498 globals->broker.RegisterCommunicationChannel(channel.get());
499 CHECK(channel->Connect());
500
501 while (true) {
502 LOG(INFO) << "Privileged process spinning run loop.";
503 base::MessageLoop::current()->Run();
504 ProxyListener::Reason reason = listener.get_reason();
505 if (reason == ProxyListener::CHANNEL_ERROR)
506 break;
507
508 while (listener.has_message()) {
509 LOG(INFO) << "Privileged process running callback.";
510 callback(channel.get(), listener.get_first_message());
511 LOG(INFO) << "Privileged process finishing callback.";
512 listener.pop_first_message();
513 }
514 }
515
516 if (active_names_at_start != IPC::GetActiveNameCount()) {
517 LOG(INFO) << "Memory leak!.";
518 }
519 LOG(INFO) << "Privileged process end.";
520 return 0;
521 }
522
523 // An unprivileged process makes a shared memory region, and writes a string to
524 // it. The SharedMemoryHandle is sent to the privileged process using Chrome
525 // IPC. The privileged process checks that it received the same memory region.
526 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
527 CommonSetUp("SendSharedMemoryHandle");
528
529 SendMessage1(kDataBuffer1);
530 base::MessageLoop::current()->Run();
531 CommonTearDown();
532 }
533
534 void SendSharedMemoryHandleCallback(IPC::Sender* sender,
535 const IPC::Message& message) {
536 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
537 SendControlMessage(sender, success);
538 }
539
540 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
541 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
542 "SendSharedMemoryHandle");
543 }
544
545 // Similar to SendSharedMemoryHandle, but sends a very long shared memory
546 // region.
547 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
548 CommonSetUp("SendSharedMemoryHandleLong");
549
550 std::string buffer(1 << 23, 'a');
551 SendMessage1(buffer);
552 base::MessageLoop::current()->Run();
553 CommonTearDown();
554 }
555
556 void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
557 const IPC::Message& message) {
558 std::string buffer(1 << 23, 'a');
559 bool success = CheckContentsOfMessage1(message, buffer);
560 SendControlMessage(sender, success);
561 }
562
563 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
564 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
565 "SendSharedMemoryHandleLong");
566 }
567
568 // Similar to SendSharedMemoryHandle, but sends two different shared memory
569 // regions in two messages.
570 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
571 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
572
573 SendMessage1(kDataBuffer1);
574 SendMessage1(kDataBuffer2);
575 base::MessageLoop::current()->Run();
576 CommonTearDown();
577 }
578
579 void SendTwoMessagesDifferentSharedMemoryHandleCallback(
580 IPC::Sender* sender,
581 const IPC::Message& message) {
582 static int count = 0;
583 static bool success = true;
584 ++count;
585 if (count == 1) {
586 success &= CheckContentsOfMessage1(message, kDataBuffer1);
587 } else if (count == 2) {
588 success &= CheckContentsOfMessage1(message, kDataBuffer2);
589 SendControlMessage(sender, success);
590 }
591 }
592
593 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
594 return CommonPrivilegedProcessMain(
595 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
596 "SendTwoMessagesDifferentSharedMemoryHandle");
597 }
598
599 // Similar to SendSharedMemoryHandle, but sends the same shared memory region in
600 // two messages.
601 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
602 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
603
604 {
605 scoped_ptr<base::SharedMemory> shared_memory(
606 MakeSharedMemory(kDataBuffer1));
607
608 for (int i = 0; i < 2; ++i) {
609 IPC::Message* message =
610 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
611 sender()->Send(message);
612 }
613 }
614
615 base::MessageLoop::current()->Run();
616 CommonTearDown();
617 }
618
619 void SendTwoMessagesSameSharedMemoryHandleCallback(
620 IPC::Sender* sender,
621 const IPC::Message& message) {
622 static int count = 0;
623 static base::SharedMemoryHandle handle1;
624 ++count;
625
626 if (count == 1) {
627 handle1 = GetSharedMemoryHandleFromMsg1(message);
628 } else if (count == 2) {
629 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
630
631 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
632 handle1, handle2, kDataBuffer1);
633 SendControlMessage(sender, success);
634 }
635 }
636
637 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
638 return CommonPrivilegedProcessMain(
639 &SendTwoMessagesSameSharedMemoryHandleCallback,
640 "SendTwoMessagesSameSharedMemoryHandle");
641 }
642
643 // Similar to SendSharedMemoryHandle, but sends one message with two different
644 // memory regions.
645 TEST_F(IPCAttachmentBrokerMacTest,
646 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
647 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
648
649 {
650 scoped_ptr<base::SharedMemory> shared_memory1(
651 MakeSharedMemory(kDataBuffer1));
652 scoped_ptr<base::SharedMemory> shared_memory2(
653 MakeSharedMemory(kDataBuffer2));
654 IPC::Message* message = new TestSharedMemoryHandleMsg2(
655 shared_memory1->handle(), shared_memory2->handle());
656 sender()->Send(message);
657 }
658 base::MessageLoop::current()->Run();
659 CommonTearDown();
660 }
661
662 void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
663 IPC::Sender* sender,
664 const IPC::Message& message) {
665 base::SharedMemoryHandle handle1;
666 base::SharedMemoryHandle handle2;
667 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
668 LOG(ERROR) << "Failed to deserialize message.";
669 SendControlMessage(sender, false);
670 return;
671 }
672
673 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
674 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
675 SendControlMessage(sender, success);
676 }
677
678 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
679 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
680 return CommonPrivilegedProcessMain(
681 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
682 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
683 }
684
685 // Similar to SendSharedMemoryHandle, but sends one message that contains the
686 // same memory region twice.
687 TEST_F(IPCAttachmentBrokerMacTest,
688 SendOneMessageWithTwoSameSharedMemoryHandles) {
689 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
690
691 {
692 scoped_ptr<base::SharedMemory> shared_memory(
693 MakeSharedMemory(kDataBuffer1));
694 IPC::Message* message = new TestSharedMemoryHandleMsg2(
695 shared_memory->handle(), shared_memory->handle());
696 sender()->Send(message);
697 }
698 base::MessageLoop::current()->Run();
699 CommonTearDown();
700 }
701
702 void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
703 IPC::Sender* sender,
704 const IPC::Message& message) {
705 base::SharedMemoryHandle handle1;
706 base::SharedMemoryHandle handle2;
707 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
708 LOG(ERROR) << "Failed to deserialize message.";
709 SendControlMessage(sender, false);
710 return;
711 }
712
713 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
714 handle1, handle2, kDataBuffer1);
715 SendControlMessage(sender, success);
716 }
717
718 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
719 SendOneMessageWithTwoSameSharedMemoryHandles) {
720 return CommonPrivilegedProcessMain(
721 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
722 "SendOneMessageWithTwoSameSharedMemoryHandles");
723 }
724
725 // Sends one message with two Posix FDs and two Mach ports.
726 TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
727 base::ScopedTempDir temp_dir;
728 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
729 base::FilePath fp1, fp2;
730 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
731 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
732
733 CommonSetUp("SendPosixFDAndMachPort");
734
735 {
736 scoped_ptr<base::SharedMemory> shared_memory1(
737 MakeSharedMemory(kDataBuffer1));
738 scoped_ptr<base::SharedMemory> shared_memory2(
739 MakeSharedMemory(kDataBuffer2));
740
741 base::FileDescriptor file_descriptor1(
742 MakeFileDescriptor(fp1, kDataBuffer3));
743 base::FileDescriptor file_descriptor2(
744 MakeFileDescriptor(fp2, kDataBuffer4));
745
746 IPC::Message* message = new TestSharedMemoryHandleMsg3(
747 file_descriptor1, shared_memory1->handle(), file_descriptor2,
748 shared_memory2->handle());
749 sender()->Send(message);
750 }
751
752 base::MessageLoop::current()->Run();
753 CommonTearDown();
754 }
755
756 void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
757 const IPC::Message& message) {
758 TestSharedMemoryHandleMsg3::Schema::Param p;
759 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
760 LOG(ERROR) << "Failed to deserialize message.";
761 SendControlMessage(sender, false);
762 return;
763 }
764
765 base::SharedMemoryHandle handle1 = base::get<1>(p);
766 base::SharedMemoryHandle handle2 = base::get<3>(p);
767 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
768 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
769 if (!success1)
770 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
771
772 bool success2 =
773 CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
774 CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
775 if (!success2)
776 LOG(ERROR) << "FileDescriptors have wrong contents.";
777
778 SendControlMessage(sender, success1 && success2);
779 }
780
781 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
782 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
783 "SendPosixFDAndMachPort");
784 }
785
786 // Similar to SendHandle, except the attachment's destination process is this
787 // process. This is an unrealistic scenario, but simulates an unprivileged
788 // process sending an attachment to another unprivileged process.
789 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
790 SetBroker(new MockBroker);
791 CommonSetUp("SendSharedMemoryHandleToSelf");
792
793 // Technically, the channel is an endpoint, but we need the proxy listener to
794 // receive the messages so that it can quit the message loop.
795 channel()->SetAttachmentBrokerEndpoint(false);
796 get_proxy_listener()->set_listener(get_broker());
797
798 {
799 scoped_ptr<base::SharedMemory> shared_memory(
800 MakeSharedMemory(kDataBuffer1));
801 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
802 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
803
804 IPC::Message* message =
805 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
806 sender()->Send(message);
807 base::MessageLoop::current()->Run();
808
809 // Get the received attachment.
810 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
811 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
812 get_broker()->GetAttachmentWithId(*id, &received_attachment);
813 ASSERT_NE(received_attachment.get(), nullptr);
814
815 // Check that it's has the same name, but that the ref count has increased.
816 base::mac::ScopedMachSendRight memory_object(
817 GetMachPortFromBrokeredAttachment(received_attachment));
818 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
819 EXPECT_EQ(ref_count + 1,
820 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
821 MACH_PORT_RIGHT_SEND));
822 }
823
824 FinalCleanUp();
825 }
826
827 void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
828 const IPC::Message&) {
829 // Do nothing special. The default behavior already runs the
830 // AttachmentBrokerPrivilegedMac.
831 }
832
833 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
834 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
835 "SendSharedMemoryHandleToSelf");
836 }
837
838 } // namespace
OLDNEW
« no previous file with comments | « ipc/BUILD.gn ('k') | ipc/attachment_broker_privileged_win_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698