blob: 3188640bfee4140635395b08a60a6fc9f5b1d144 [file] [log] [blame]
erikchenb82097cc2015-10-12 23:27:551// 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"
erikchen328bf3f2015-10-24 00:46:5414#include "base/mac/mac_util.h"
erikchenb82097cc2015-10-12 23:27:5515#include "base/memory/scoped_ptr.h"
16#include "base/memory/shared_memory.h"
17#include "ipc/attachment_broker_privileged_mac.h"
18#include "ipc/attachment_broker_unprivileged_mac.h"
19#include "ipc/ipc_listener.h"
20#include "ipc/ipc_message.h"
21#include "ipc/ipc_test_base.h"
22#include "ipc/ipc_test_messages.h"
23#include "ipc/test_util_mac.h"
24
25namespace {
26
27const char kDataBuffer1[] = "This is some test data to write to the file.";
28const char kDataBuffer2[] = "The lazy dog and a fox.";
29const char kDataBuffer3[] = "Two green bears but not a potato.";
30const char kDataBuffer4[] = "Red potato is best potato.";
31const std::string g_service_switch_name = "service_name";
32
33enum TestResult {
34 RESULT_UNKNOWN,
35 RESULT_SUCCESS,
36 RESULT_FAILURE,
37};
38
39base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
40 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
41 if (attachment->GetType() !=
42 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
43 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
44 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
45 }
46
47 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
48 LOG(INFO) << "Brokerable type not MACH_PORT.";
49 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
50 }
51
52 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
53 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
54 return base::mac::ScopedMachSendRight(
55 received_mach_port_attachment->get_mach_port());
56}
57
58// Makes a Mach port backed SharedMemory region and fills it with |contents|.
59scoped_ptr<base::SharedMemory> MakeSharedMemory(const std::string& contents) {
60 base::SharedMemoryHandle shm(contents.size());
61 if (!shm.IsValid()) {
62 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
63 return nullptr;
64 }
65 scoped_ptr<base::SharedMemory> shared_memory(
66 new base::SharedMemory(shm, false));
67 shared_memory->Map(contents.size());
68 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
69 return shared_memory;
70}
71
72// |message| must be deserializable as a TestSharedMemoryHandleMsg1.
73base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
74 const IPC::Message& message) {
75 // Expect a message with a brokered attachment.
76 if (!message.HasBrokerableAttachments()) {
77 LOG(ERROR) << "Message missing brokerable attachment.";
78 return base::SharedMemoryHandle();
79 }
80
81 TestSharedMemoryHandleMsg1::Schema::Param p;
82 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
83 LOG(ERROR) << "Failed to deserialize message.";
84 return base::SharedMemoryHandle();
85 }
86
87 return base::get<1>(p);
88}
89
90// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
91// whether deserialization was successful. |handle1| and |handle2| are output
92// variables populated on success.
93bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
94 base::SharedMemoryHandle* handle1,
95 base::SharedMemoryHandle* handle2) {
96 // Expect a message with a brokered attachment.
97 if (!message.HasBrokerableAttachments()) {
98 LOG(ERROR) << "Message missing brokerable attachment.";
99 return false;
100 }
101
102 TestSharedMemoryHandleMsg2::Schema::Param p;
103 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
104 LOG(ERROR) << "Failed to deserialize message.";
105 return false;
106 }
107
108 *handle1 = base::get<0>(p);
109 *handle2 = base::get<1>(p);
110 return true;
111}
112
113// Returns |nullptr| on error.
114scoped_ptr<base::SharedMemory> MapSharedMemoryHandle(
erikchen328bf3f2015-10-24 00:46:54115 const base::SharedMemoryHandle& shm,
116 bool read_only) {
erikchenb82097cc2015-10-12 23:27:55117 if (!shm.IsValid()) {
118 LOG(ERROR) << "Invalid SharedMemoryHandle";
119 return nullptr;
120 }
121
122 size_t size;
123 if (!shm.GetSize(&size)) {
124 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
125 return nullptr;
126 }
127
128 scoped_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:54129 new base::SharedMemory(shm, read_only));
erikchenb82097cc2015-10-12 23:27:55130 shared_memory->Map(size);
131 return shared_memory;
132}
133
134// This method maps the SharedMemoryHandle, checks the contents, and then
135// consumes a reference to the underlying Mach port.
136bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
137 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54138 scoped_ptr<base::SharedMemory> shared_memory(
139 MapSharedMemoryHandle(shm, false));
erikchenb82097cc2015-10-12 23:27:55140
141 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
142 LOG(ERROR) << "Shared Memory contents not equivalent";
143 return false;
144 }
145 return true;
146}
147
148// This method mmaps the FileDescriptor, checks the contents, and then munmaps
149// the FileDescriptor and closes the underlying fd.
150bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
151 const std::string& contents) {
152 base::ScopedFD fd_closer(file_descriptor.fd);
153 lseek(file_descriptor.fd, 0, SEEK_SET);
154 scoped_ptr<char, base::FreeDeleter> buffer(
155 static_cast<char*>(malloc(contents.size())));
156 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
157 return false;
158
159 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
160 return result == 0;
161}
162
163// Open |fp| and populate it with |contents|.
164base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
165 const std::string& contents) {
166 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
167 base::ScopedFD fd_closer(fd);
168 if (fd <= 0) {
169 LOG(ERROR) << "Error opening file at: " << fp.value();
170 return base::FileDescriptor();
171 }
172
173 if (lseek(fd, 0, SEEK_SET) != 0) {
174 LOG(ERROR) << "Error changing offset";
175 return base::FileDescriptor();
176 }
177
178 if (write(fd, contents.c_str(), contents.size()) !=
179 static_cast<ssize_t>(contents.size())) {
180 LOG(ERROR) << "Error writing to file";
181 return base::FileDescriptor();
182 }
183
184 return base::FileDescriptor(fd_closer.release(), true);
185}
186
187// Maps both handles, then checks that their contents matches |contents|. Then
188// checks that changes to one are reflected in the other. Then consumes
189// references to both underlying Mach ports.
190bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
191 const base::SharedMemoryHandle& handle1,
192 const base::SharedMemoryHandle& handle2,
193 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54194 scoped_ptr<base::SharedMemory> shared_memory1(
195 MapSharedMemoryHandle(handle1, false));
196 scoped_ptr<base::SharedMemory> shared_memory2(
197 MapSharedMemoryHandle(handle2, false));
erikchenb82097cc2015-10-12 23:27:55198
199 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
200 0) {
201 LOG(ERROR) << "Incorrect contents in shared_memory1";
202 return false;
203 }
204
205 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
206 contents.size()) != 0) {
207 LOG(ERROR) << "Incorrect contents in shared_memory2";
208 return false;
209 }
210
211 // Updating shared_memory1 should update shared_memory2.
212 const char known_string[] = "string bean";
213 if (shared_memory1->mapped_size() < strlen(known_string) ||
214 shared_memory2->mapped_size() < strlen(known_string)) {
215 LOG(ERROR) << "Shared memory size is too small";
216 return false;
217 }
218 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
219
220 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
221 strlen(known_string)) != 0) {
222 LOG(ERROR) << "Incorrect contents in shared_memory2";
223 return false;
224 }
225
226 return true;
227}
228
229// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
230// whether the contents of the attached shared memory region matches |contents|.
231// Consumes a reference to the underlying Mach port.
232bool CheckContentsOfMessage1(const IPC::Message& message,
233 const std::string& contents) {
234 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
235 return CheckContentsOfSharedMemoryHandle(shm, contents);
236}
237
238// Once the test is finished, send a control message to the parent process with
239// the result. The message may require the runloop to be run before its
240// dispatched.
241void SendControlMessage(IPC::Sender* sender, bool success) {
242 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
243 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
244 message->WriteInt(result);
245 sender->Send(message);
246}
247
248// Records the most recently received brokerable attachment's id.
249class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
250 public:
251 void ReceivedBrokerableAttachmentWithId(
252 const IPC::BrokerableAttachment::AttachmentId& id) override {
253 id_ = id;
254 }
255 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
256
257 private:
258 IPC::BrokerableAttachment::AttachmentId id_;
259};
260
261// A broker which always sets the current process as the destination process
262// for attachments.
263class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
264 public:
265 MockBroker() {}
266 ~MockBroker() override {}
erikchena03dde6f2015-10-29 22:37:04267 bool SendAttachmentToProcess(
268 const scoped_refptr<IPC::BrokerableAttachment>& attachment,
269 base::ProcessId destination_process) override {
erikchenb82097cc2015-10-12 23:27:55270 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
271 attachment, base::Process::Current().Pid());
272 }
273};
274
275// Forwards all messages to |listener_|. Quits the message loop after a
276// message is received, or the channel has an error.
277class ProxyListener : public IPC::Listener {
278 public:
279 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
280 ~ProxyListener() override {}
281
282 // The reason for exiting the message loop.
283 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
284
285 bool OnMessageReceived(const IPC::Message& message) override {
286 bool result = false;
287 if (listener_)
288 result = listener_->OnMessageReceived(message);
289 reason_ = MESSAGE_RECEIVED;
290 messages_.push_back(message);
291 base::MessageLoop::current()->QuitNow();
292 return result;
293 }
294
295 void OnChannelError() override {
296 reason_ = CHANNEL_ERROR;
297 base::MessageLoop::current()->QuitNow();
298 }
299
300 void set_listener(IPC::Listener* listener) { listener_ = listener; }
301 Reason get_reason() { return reason_; }
302 IPC::Message get_first_message() {
303 DCHECK(!messages_.empty());
304 return messages_[0];
305 }
306 void pop_first_message() {
307 DCHECK(!messages_.empty());
308 messages_.erase(messages_.begin());
309 }
310 bool has_message() { return !messages_.empty(); }
311
312 private:
313 IPC::Listener* listener_;
314 Reason reason_;
315 std::vector<IPC::Message> messages_;
316};
317
318// Waits for a result to be sent over the channel. Quits the message loop
319// after a message is received, or the channel has an error.
320class ResultListener : public IPC::Listener {
321 public:
322 ResultListener() : result_(RESULT_UNKNOWN) {}
323 ~ResultListener() override {}
324
325 bool OnMessageReceived(const IPC::Message& message) override {
326 base::PickleIterator iter(message);
327
328 int result;
329 EXPECT_TRUE(iter.ReadInt(&result));
330 result_ = static_cast<TestResult>(result);
331 return true;
332 }
333
334 TestResult get_result() { return result_; }
335
336 private:
337 TestResult result_;
338};
339
340class MockPortProvider : public base::PortProvider {
341 public:
342 mach_port_t TaskForPid(base::ProcessHandle process) const override {
343 auto it = port_map_.find(process);
344 if (it != port_map_.end())
345 return it->second;
346 return MACH_PORT_NULL;
347 }
348
349 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
350 port_map_[process] = task_port;
351 }
352
353 private:
354 std::map<base::ProcessHandle, mach_port_t> port_map_;
355};
356
357// End-to-end tests for the attachment brokering process on Mac.
358// The parent process acts as an unprivileged process. The child process acts
359// as the privileged process.
360class IPCAttachmentBrokerMacTest : public IPCTestBase {
361 public:
362 IPCAttachmentBrokerMacTest() {}
363 ~IPCAttachmentBrokerMacTest() override {}
364
365 base::CommandLine MakeCmdLine(const std::string& procname) override {
366 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
367 // Pass the service name to the child process.
368 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
369 return command_line;
370 }
371
372 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
373 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
374 broker_.reset(broker);
375 }
376
erikchen24e44d32015-10-21 22:28:54377 // Mach Setup that needs to occur before child processes are forked.
378 void MachPreForkSetUp() {
379 service_name_ = IPC::CreateRandomServiceName();
380 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
381 }
382
383 // Mach Setup that needs to occur after child processes are forked.
384 void MachPostForkSetUp() {
385 client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
386 IPC::SendMachPort(
387 client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
388 }
389
erikchenb82097cc2015-10-12 23:27:55390 // Setup shared between tests.
391 void CommonSetUp(const char* name) {
392 Init(name);
erikchen24e44d32015-10-21 22:28:54393 MachPreForkSetUp();
erikchenb82097cc2015-10-12 23:27:55394
395 if (!broker_.get())
396 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
397
erikchen94c9b702015-11-06 21:12:36398 broker_->AddObserver(&observer_, task_runner());
erikchenb82097cc2015-10-12 23:27:55399 CreateChannel(&proxy_listener_);
400 broker_->DesignateBrokerCommunicationChannel(channel());
401 ASSERT_TRUE(ConnectChannel());
402 ASSERT_TRUE(StartClient());
403
erikchen24e44d32015-10-21 22:28:54404 MachPostForkSetUp();
erikchenb82097cc2015-10-12 23:27:55405 active_names_at_start_ = IPC::GetActiveNameCount();
406 get_proxy_listener()->set_listener(&result_listener_);
407 }
408
409 void CheckChildResult() {
410 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
411 get_proxy_listener()->get_reason());
412 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
413 }
414
415 void FinalCleanUp() {
416 // There should be no leaked names.
417 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
418
419 // Close the channel so the client's OnChannelError() gets fired.
420 channel()->Close();
421
422 EXPECT_TRUE(WaitForClientShutdown());
423 DestroyChannel();
424 broker_.reset();
425 }
426
427 // Teardown shared between most tests.
428 void CommonTearDown() {
429 CheckChildResult();
430 FinalCleanUp();
431 }
432
433 // Makes a SharedMemory region, fills it with |contents|, sends the handle
434 // over Chrome IPC, and unmaps the region.
435 void SendMessage1(const std::string& contents) {
436 scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
437 IPC::Message* message =
438 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
439 sender()->Send(message);
440 }
441
442 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
443 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
444 AttachmentBrokerObserver* get_observer() { return &observer_; }
445 ResultListener* get_result_listener() { return &result_listener_; }
446
erikchen24e44d32015-10-21 22:28:54447 protected:
448 // The number of active names immediately after set up.
449 mach_msg_type_number_t active_names_at_start_;
450
erikchenb82097cc2015-10-12 23:27:55451 private:
452 ProxyListener proxy_listener_;
453 scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
454 AttachmentBrokerObserver observer_;
455
456 // A port on which the main process listens for mach messages from the child
457 // process.
458 base::mac::ScopedMachReceiveRight server_port_;
459
460 // A port on which the child process listens for mach messages from the main
461 // process.
462 base::mac::ScopedMachSendRight client_port_;
463
erikchenb82097cc2015-10-12 23:27:55464 std::string service_name_;
465
466 ResultListener result_listener_;
467};
468
469using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
470 const IPC::Message& message);
471
472// These objects are globally accessible, and are expected to outlive all IPC
473// Channels.
474struct ChildProcessGlobals {
erikchend8a3d9022015-10-22 20:02:02475 scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
erikchenb82097cc2015-10-12 23:27:55476 MockPortProvider port_provider;
477 base::mac::ScopedMachSendRight server_task_port;
478};
479
480// Sets up the Mach communication ports with the server. Returns a set of
481// globals that must live at least as long as the test.
482scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
483 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
484 std::string service_name =
485 cmd_line.GetSwitchValueASCII(g_service_switch_name);
486 base::mac::ScopedMachSendRight server_port(
487 IPC::LookupServer(service_name.c_str()));
488 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
489
490 // Send the port that this process is listening on to the server.
markda902e182015-10-20 18:36:13491 IPC::SendMachPort(
492 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
erikchenb82097cc2015-10-12 23:27:55493
494 // Receive the task port of the server process.
495 base::mac::ScopedMachSendRight server_task_port(
markda902e182015-10-20 18:36:13496 IPC::ReceiveMachPort(client_port.get()));
erikchenb82097cc2015-10-12 23:27:55497
498 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
erikchend8a3d9022015-10-22 20:02:02499 globals->broker.reset(
500 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
markda902e182015-10-20 18:36:13501 globals->port_provider.InsertEntry(getppid(), server_task_port.get());
erikchenb82097cc2015-10-12 23:27:55502 globals->server_task_port.reset(server_task_port.release());
503 return globals;
504}
505
506int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
507 const char* channel_name) {
508 LOG(INFO) << "Privileged process start.";
509 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
510
511 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
512
513 base::MessageLoopForIO main_message_loop;
514 ProxyListener listener;
515
516 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
517 IPCTestBase::GetChannelName(channel_name), &listener));
erikchend8a3d9022015-10-22 20:02:02518 globals->broker->RegisterCommunicationChannel(channel.get());
erikchenb82097cc2015-10-12 23:27:55519 CHECK(channel->Connect());
520
521 while (true) {
522 LOG(INFO) << "Privileged process spinning run loop.";
523 base::MessageLoop::current()->Run();
524 ProxyListener::Reason reason = listener.get_reason();
525 if (reason == ProxyListener::CHANNEL_ERROR)
526 break;
527
528 while (listener.has_message()) {
529 LOG(INFO) << "Privileged process running callback.";
530 callback(channel.get(), listener.get_first_message());
531 LOG(INFO) << "Privileged process finishing callback.";
532 listener.pop_first_message();
533 }
534 }
535
536 if (active_names_at_start != IPC::GetActiveNameCount()) {
537 LOG(INFO) << "Memory leak!.";
538 }
539 LOG(INFO) << "Privileged process end.";
540 return 0;
541}
542
543// An unprivileged process makes a shared memory region, and writes a string to
544// it. The SharedMemoryHandle is sent to the privileged process using Chrome
545// IPC. The privileged process checks that it received the same memory region.
546TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54547 // Mach-based SharedMemory isn't support on OSX 10.6.
548 if (base::mac::IsOSSnowLeopard())
549 return;
550
erikchenb82097cc2015-10-12 23:27:55551 CommonSetUp("SendSharedMemoryHandle");
552
553 SendMessage1(kDataBuffer1);
554 base::MessageLoop::current()->Run();
555 CommonTearDown();
556}
557
558void SendSharedMemoryHandleCallback(IPC::Sender* sender,
559 const IPC::Message& message) {
560 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
561 SendControlMessage(sender, success);
562}
563
564MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
565 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
566 "SendSharedMemoryHandle");
567}
568
569// Similar to SendSharedMemoryHandle, but sends a very long shared memory
570// region.
571TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
erikchen328bf3f2015-10-24 00:46:54572 // Mach-based SharedMemory isn't support on OSX 10.6.
573 if (base::mac::IsOSSnowLeopard())
574 return;
575
erikchenb82097cc2015-10-12 23:27:55576 CommonSetUp("SendSharedMemoryHandleLong");
577
578 std::string buffer(1 << 23, 'a');
579 SendMessage1(buffer);
580 base::MessageLoop::current()->Run();
581 CommonTearDown();
582}
583
584void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
585 const IPC::Message& message) {
586 std::string buffer(1 << 23, 'a');
587 bool success = CheckContentsOfMessage1(message, buffer);
588 SendControlMessage(sender, success);
589}
590
591MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
592 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
593 "SendSharedMemoryHandleLong");
594}
595
596// Similar to SendSharedMemoryHandle, but sends two different shared memory
597// regions in two messages.
598TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54599 // Mach-based SharedMemory isn't support on OSX 10.6.
600 if (base::mac::IsOSSnowLeopard())
601 return;
602
erikchenb82097cc2015-10-12 23:27:55603 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
604
605 SendMessage1(kDataBuffer1);
606 SendMessage1(kDataBuffer2);
607 base::MessageLoop::current()->Run();
608 CommonTearDown();
609}
610
611void SendTwoMessagesDifferentSharedMemoryHandleCallback(
612 IPC::Sender* sender,
613 const IPC::Message& message) {
614 static int count = 0;
615 static bool success = true;
616 ++count;
617 if (count == 1) {
618 success &= CheckContentsOfMessage1(message, kDataBuffer1);
619 } else if (count == 2) {
620 success &= CheckContentsOfMessage1(message, kDataBuffer2);
621 SendControlMessage(sender, success);
622 }
623}
624
625MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
626 return CommonPrivilegedProcessMain(
627 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
628 "SendTwoMessagesDifferentSharedMemoryHandle");
629}
630
631// Similar to SendSharedMemoryHandle, but sends the same shared memory region in
632// two messages.
633TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54634 // Mach-based SharedMemory isn't support on OSX 10.6.
635 if (base::mac::IsOSSnowLeopard())
636 return;
637
erikchenb82097cc2015-10-12 23:27:55638 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
639
640 {
641 scoped_ptr<base::SharedMemory> shared_memory(
642 MakeSharedMemory(kDataBuffer1));
643
644 for (int i = 0; i < 2; ++i) {
645 IPC::Message* message =
646 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
647 sender()->Send(message);
648 }
649 }
650
651 base::MessageLoop::current()->Run();
652 CommonTearDown();
653}
654
655void SendTwoMessagesSameSharedMemoryHandleCallback(
656 IPC::Sender* sender,
657 const IPC::Message& message) {
658 static int count = 0;
659 static base::SharedMemoryHandle handle1;
660 ++count;
661
662 if (count == 1) {
663 handle1 = GetSharedMemoryHandleFromMsg1(message);
664 } else if (count == 2) {
665 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
666
667 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
668 handle1, handle2, kDataBuffer1);
669 SendControlMessage(sender, success);
670 }
671}
672
673MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
674 return CommonPrivilegedProcessMain(
675 &SendTwoMessagesSameSharedMemoryHandleCallback,
676 "SendTwoMessagesSameSharedMemoryHandle");
677}
678
679// Similar to SendSharedMemoryHandle, but sends one message with two different
680// memory regions.
681TEST_F(IPCAttachmentBrokerMacTest,
682 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
erikchen328bf3f2015-10-24 00:46:54683 // Mach-based SharedMemory isn't support on OSX 10.6.
684 if (base::mac::IsOSSnowLeopard())
685 return;
686
erikchenb82097cc2015-10-12 23:27:55687 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
688
689 {
690 scoped_ptr<base::SharedMemory> shared_memory1(
691 MakeSharedMemory(kDataBuffer1));
692 scoped_ptr<base::SharedMemory> shared_memory2(
693 MakeSharedMemory(kDataBuffer2));
694 IPC::Message* message = new TestSharedMemoryHandleMsg2(
695 shared_memory1->handle(), shared_memory2->handle());
696 sender()->Send(message);
697 }
698 base::MessageLoop::current()->Run();
699 CommonTearDown();
700}
701
702void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
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 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
714 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
715 SendControlMessage(sender, success);
716}
717
718MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
719 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
720 return CommonPrivilegedProcessMain(
721 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
722 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
723}
724
725// Similar to SendSharedMemoryHandle, but sends one message that contains the
726// same memory region twice.
727TEST_F(IPCAttachmentBrokerMacTest,
728 SendOneMessageWithTwoSameSharedMemoryHandles) {
erikchen328bf3f2015-10-24 00:46:54729 // Mach-based SharedMemory isn't support on OSX 10.6.
730 if (base::mac::IsOSSnowLeopard())
731 return;
732
erikchenb82097cc2015-10-12 23:27:55733 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
734
735 {
736 scoped_ptr<base::SharedMemory> shared_memory(
737 MakeSharedMemory(kDataBuffer1));
738 IPC::Message* message = new TestSharedMemoryHandleMsg2(
739 shared_memory->handle(), shared_memory->handle());
740 sender()->Send(message);
741 }
742 base::MessageLoop::current()->Run();
743 CommonTearDown();
744}
745
746void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
747 IPC::Sender* sender,
748 const IPC::Message& message) {
749 base::SharedMemoryHandle handle1;
750 base::SharedMemoryHandle handle2;
751 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
752 LOG(ERROR) << "Failed to deserialize message.";
753 SendControlMessage(sender, false);
754 return;
755 }
756
757 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
758 handle1, handle2, kDataBuffer1);
759 SendControlMessage(sender, success);
760}
761
762MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
763 SendOneMessageWithTwoSameSharedMemoryHandles) {
764 return CommonPrivilegedProcessMain(
765 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
766 "SendOneMessageWithTwoSameSharedMemoryHandles");
767}
768
769// Sends one message with two Posix FDs and two Mach ports.
770TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
erikchen328bf3f2015-10-24 00:46:54771 // Mach-based SharedMemory isn't support on OSX 10.6.
772 if (base::mac::IsOSSnowLeopard())
773 return;
774
erikchenb82097cc2015-10-12 23:27:55775 base::ScopedTempDir temp_dir;
776 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
777 base::FilePath fp1, fp2;
778 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
779 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
780
781 CommonSetUp("SendPosixFDAndMachPort");
782
783 {
784 scoped_ptr<base::SharedMemory> shared_memory1(
785 MakeSharedMemory(kDataBuffer1));
786 scoped_ptr<base::SharedMemory> shared_memory2(
787 MakeSharedMemory(kDataBuffer2));
788
789 base::FileDescriptor file_descriptor1(
790 MakeFileDescriptor(fp1, kDataBuffer3));
791 base::FileDescriptor file_descriptor2(
792 MakeFileDescriptor(fp2, kDataBuffer4));
793
794 IPC::Message* message = new TestSharedMemoryHandleMsg3(
795 file_descriptor1, shared_memory1->handle(), file_descriptor2,
796 shared_memory2->handle());
797 sender()->Send(message);
798 }
799
800 base::MessageLoop::current()->Run();
801 CommonTearDown();
802}
803
804void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
805 const IPC::Message& message) {
806 TestSharedMemoryHandleMsg3::Schema::Param p;
807 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
808 LOG(ERROR) << "Failed to deserialize message.";
809 SendControlMessage(sender, false);
810 return;
811 }
812
813 base::SharedMemoryHandle handle1 = base::get<1>(p);
814 base::SharedMemoryHandle handle2 = base::get<3>(p);
815 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
816 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
817 if (!success1)
818 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
819
820 bool success2 =
821 CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
822 CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
823 if (!success2)
824 LOG(ERROR) << "FileDescriptors have wrong contents.";
825
826 SendControlMessage(sender, success1 && success2);
827}
828
829MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
830 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
831 "SendPosixFDAndMachPort");
832}
833
834// Similar to SendHandle, except the attachment's destination process is this
835// process. This is an unrealistic scenario, but simulates an unprivileged
836// process sending an attachment to another unprivileged process.
837TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
erikchen328bf3f2015-10-24 00:46:54838 // Mach-based SharedMemory isn't support on OSX 10.6.
839 if (base::mac::IsOSSnowLeopard())
840 return;
841
erikchenb82097cc2015-10-12 23:27:55842 SetBroker(new MockBroker);
843 CommonSetUp("SendSharedMemoryHandleToSelf");
844
845 // Technically, the channel is an endpoint, but we need the proxy listener to
846 // receive the messages so that it can quit the message loop.
847 channel()->SetAttachmentBrokerEndpoint(false);
848 get_proxy_listener()->set_listener(get_broker());
849
850 {
851 scoped_ptr<base::SharedMemory> shared_memory(
852 MakeSharedMemory(kDataBuffer1));
853 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
854 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
855
856 IPC::Message* message =
857 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
858 sender()->Send(message);
erikchen94c9b702015-11-06 21:12:36859
860 // Wait until the child process has sent this process a message.
erikchenb82097cc2015-10-12 23:27:55861 base::MessageLoop::current()->Run();
862
erikchen94c9b702015-11-06 21:12:36863 // Wait for any asynchronous activity to complete.
864 base::MessageLoop::current()->RunUntilIdle();
865
erikchenb82097cc2015-10-12 23:27:55866 // Get the received attachment.
867 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
erikchen94c9b702015-11-06 21:12:36868 ASSERT_TRUE(id);
erikchenb82097cc2015-10-12 23:27:55869 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
870 get_broker()->GetAttachmentWithId(*id, &received_attachment);
871 ASSERT_NE(received_attachment.get(), nullptr);
872
873 // Check that it's has the same name, but that the ref count has increased.
874 base::mac::ScopedMachSendRight memory_object(
875 GetMachPortFromBrokeredAttachment(received_attachment));
876 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
877 EXPECT_EQ(ref_count + 1,
878 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
879 MACH_PORT_RIGHT_SEND));
880 }
881
882 FinalCleanUp();
883}
884
885void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
886 const IPC::Message&) {
887 // Do nothing special. The default behavior already runs the
888 // AttachmentBrokerPrivilegedMac.
889}
890
891MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
892 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
893 "SendSharedMemoryHandleToSelf");
894}
895
erikchen24e44d32015-10-21 22:28:54896// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
897// Channel.
898TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
erikchen328bf3f2015-10-24 00:46:54899 // Mach-based SharedMemory isn't support on OSX 10.6.
900 if (base::mac::IsOSSnowLeopard())
901 return;
902
erikchen24e44d32015-10-21 22:28:54903 Init("SendSharedMemoryHandleChannelProxy");
904 MachPreForkSetUp();
905
906 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
erikchen94c9b702015-11-06 21:12:36907 get_broker()->AddObserver(get_observer(), task_runner());
erikchen24e44d32015-10-21 22:28:54908
909 scoped_ptr<base::Thread> thread(
910 new base::Thread("ChannelProxyTestServerThread"));
911 base::Thread::Options options;
912 options.message_loop_type = base::MessageLoop::TYPE_IO;
913 thread->StartWithOptions(options);
914
915 CreateChannelProxy(get_proxy_listener(), thread->task_runner().get());
916 get_broker()->DesignateBrokerCommunicationChannel(channel_proxy());
917
918 ASSERT_TRUE(StartClient());
919
920 MachPostForkSetUp();
921 active_names_at_start_ = IPC::GetActiveNameCount();
922 get_proxy_listener()->set_listener(get_result_listener());
923
924 SendMessage1(kDataBuffer1);
925 base::MessageLoop::current()->Run();
926
927 CheckChildResult();
928
929 // There should be no leaked names.
930 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
931
932 // Close the channel so the client's OnChannelError() gets fired.
933 channel_proxy()->Close();
934
935 EXPECT_TRUE(WaitForClientShutdown());
936 DestroyChannelProxy();
937}
938
939void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
940 const IPC::Message& message) {
941 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
942 SendControlMessage(sender, success);
943}
944
945MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
946 return CommonPrivilegedProcessMain(
947 &SendSharedMemoryHandleChannelProxyCallback,
948 "SendSharedMemoryHandleChannelProxy");
949}
950
erikchen328bf3f2015-10-24 00:46:54951// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
952// ShareToProcess().
953TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
954 // Mach-based SharedMemory isn't support on OSX 10.6.
955 if (base::mac::IsOSSnowLeopard())
956 return;
957
958 CommonSetUp("ShareToProcess");
959
960 {
961 scoped_ptr<base::SharedMemory> shared_memory(
962 MakeSharedMemory(kDataBuffer1));
963 base::SharedMemoryHandle new_handle;
964 ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
965 IPC::Message* message =
966 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
967 sender()->Send(message);
968 }
969
970 base::MessageLoop::current()->Run();
971 CommonTearDown();
972}
973
974void ShareToProcessCallback(IPC::Sender* sender, const IPC::Message& message) {
975 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
976 SendControlMessage(sender, success);
977}
978
979MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
980 return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
981}
982
983// Similar to ShareToProcess, but instead shares the memory object only with
984// read permissions.
985TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
986 // Mach-based SharedMemory isn't support on OSX 10.6.
987 if (base::mac::IsOSSnowLeopard())
988 return;
989
990 CommonSetUp("ShareReadOnlyToProcess");
991
992 {
993 scoped_ptr<base::SharedMemory> shared_memory(
994 MakeSharedMemory(kDataBuffer1));
995 base::SharedMemoryHandle new_handle;
996 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
997 IPC::Message* message =
998 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
999 sender()->Send(message);
1000 }
1001
1002 base::MessageLoop::current()->Run();
1003 CommonTearDown();
1004}
1005
1006void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
1007 const IPC::Message& message) {
1008 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1009
1010 // Try to map the memory as writable.
1011 scoped_ptr<base::SharedMemory> shared_memory(
1012 MapSharedMemoryHandle(shm, false));
1013 ASSERT_EQ(nullptr, shared_memory->memory());
1014
1015 // Now try as read-only.
1016 scoped_ptr<base::SharedMemory> shared_memory2(
1017 MapSharedMemoryHandle(shm.Duplicate(), true));
1018 int current_prot, max_prot;
1019 ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
1020 shared_memory2->mapped_size(),
1021 &current_prot, &max_prot));
1022 ASSERT_EQ(VM_PROT_READ, current_prot);
1023 ASSERT_EQ(VM_PROT_READ, max_prot);
1024
1025 bool success =
1026 memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
1027 SendControlMessage(sender, success);
1028}
1029
1030MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
1031 return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
1032 "ShareReadOnlyToProcess");
1033}
1034
erikchenb82097cc2015-10-12 23:27:551035} // namespace