blob: 62b7d1132f0102a18f72b23dbda9d0156e19f464 [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>
erikchene50acd882015-11-24 18:28:488#include <mach/mach_vm.h>
avi246998d82015-12-22 02:39:049#include <stddef.h>
erikchenb82097cc2015-10-12 23:27:5510#include <sys/mman.h>
11
danakj03de39b22016-04-23 04:21:0912#include <memory>
tzik55e3e4d2016-03-08 05:47:4413#include <tuple>
14
erikchenb82097cc2015-10-12 23:27:5515#include "base/command_line.h"
16#include "base/files/file_util.h"
17#include "base/files/scoped_file.h"
18#include "base/files/scoped_temp_dir.h"
erikchen328bf3f2015-10-24 00:46:5419#include "base/mac/mac_util.h"
erikchene50acd882015-11-24 18:28:4820#include "base/mac/mach_logging.h"
dchengdb5935f2016-03-26 00:16:2721#include "base/memory/free_deleter.h"
erikchenb82097cc2015-10-12 23:27:5522#include "base/memory/shared_memory.h"
fdoray8e32586852016-06-22 19:56:1623#include "base/run_loop.h"
erikchene50acd882015-11-24 18:28:4824#include "base/strings/string_number_conversions.h"
25#include "base/synchronization/spin_wait.h"
26#include "base/time/time.h"
erikchen7c556432015-11-11 22:07:2727#include "ipc/attachment_broker_messages.h"
erikchenb82097cc2015-10-12 23:27:5528#include "ipc/attachment_broker_privileged_mac.h"
29#include "ipc/attachment_broker_unprivileged_mac.h"
30#include "ipc/ipc_listener.h"
31#include "ipc/ipc_message.h"
32#include "ipc/ipc_test_base.h"
33#include "ipc/ipc_test_messages.h"
34#include "ipc/test_util_mac.h"
35
36namespace {
37
38const char kDataBuffer1[] = "This is some test data to write to the file.";
39const char kDataBuffer2[] = "The lazy dog and a fox.";
40const char kDataBuffer3[] = "Two green bears but not a potato.";
41const char kDataBuffer4[] = "Red potato is best potato.";
42const std::string g_service_switch_name = "service_name";
erikchene50acd882015-11-24 18:28:4843const size_t g_large_message_size = 8 * 1024 * 1024;
44const int g_large_message_count = 1000;
45const size_t g_medium_message_size = 512 * 1024;
46
47// Running the message loop is expected to increase the number of resident
48// pages. The exact amount is non-deterministic, but for a simple test suite
49// like this one, the increase is expected to be less than 1 MB.
50const size_t g_expected_memory_increase = 1024 * 1024;
erikchenb82097cc2015-10-12 23:27:5551
52enum TestResult {
53 RESULT_UNKNOWN,
54 RESULT_SUCCESS,
55 RESULT_FAILURE,
56};
57
erikchene50acd882015-11-24 18:28:4858mach_vm_size_t GetResidentSize() {
59 task_basic_info_64 info;
60 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
61 kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
62 reinterpret_cast<task_info_t>(&info), &count);
63 MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size.";
64
65 return info.resident_size;
66}
67
erikchenb82097cc2015-10-12 23:27:5568base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
69 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
70 if (attachment->GetType() !=
71 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
72 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
73 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
74 }
75
76 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
77 LOG(INFO) << "Brokerable type not MACH_PORT.";
78 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
79 }
80
81 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
82 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
erikchen8a6f3f4e2016-01-06 22:04:4383 base::mac::ScopedMachSendRight send_right(
erikchenb82097cc2015-10-12 23:27:5584 received_mach_port_attachment->get_mach_port());
erikchen8a6f3f4e2016-01-06 22:04:4385 received_mach_port_attachment->reset_mach_port_ownership();
86 return send_right;
erikchenb82097cc2015-10-12 23:27:5587}
88
89// Makes a Mach port backed SharedMemory region and fills it with |contents|.
danakj03de39b22016-04-23 04:21:0990std::unique_ptr<base::SharedMemory> MakeSharedMemory(
91 const std::string& contents) {
erikchenb82097cc2015-10-12 23:27:5592 base::SharedMemoryHandle shm(contents.size());
93 if (!shm.IsValid()) {
94 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
95 return nullptr;
96 }
danakj03de39b22016-04-23 04:21:0997 std::unique_ptr<base::SharedMemory> shared_memory(
erikchenb82097cc2015-10-12 23:27:5598 new base::SharedMemory(shm, false));
99 shared_memory->Map(contents.size());
100 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
101 return shared_memory;
102}
103
104// |message| must be deserializable as a TestSharedMemoryHandleMsg1.
105base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
106 const IPC::Message& message) {
107 // Expect a message with a brokered attachment.
108 if (!message.HasBrokerableAttachments()) {
109 LOG(ERROR) << "Message missing brokerable attachment.";
110 return base::SharedMemoryHandle();
111 }
112
113 TestSharedMemoryHandleMsg1::Schema::Param p;
114 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
115 LOG(ERROR) << "Failed to deserialize message.";
116 return base::SharedMemoryHandle();
117 }
118
tzik55e3e4d2016-03-08 05:47:44119 return std::get<1>(p);
erikchenb82097cc2015-10-12 23:27:55120}
121
122// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
123// whether deserialization was successful. |handle1| and |handle2| are output
124// variables populated on success.
125bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
126 base::SharedMemoryHandle* handle1,
127 base::SharedMemoryHandle* handle2) {
128 // Expect a message with a brokered attachment.
129 if (!message.HasBrokerableAttachments()) {
130 LOG(ERROR) << "Message missing brokerable attachment.";
131 return false;
132 }
133
134 TestSharedMemoryHandleMsg2::Schema::Param p;
135 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
136 LOG(ERROR) << "Failed to deserialize message.";
137 return false;
138 }
139
tzik55e3e4d2016-03-08 05:47:44140 *handle1 = std::get<0>(p);
141 *handle2 = std::get<1>(p);
erikchenb82097cc2015-10-12 23:27:55142 return true;
143}
144
145// Returns |nullptr| on error.
danakj03de39b22016-04-23 04:21:09146std::unique_ptr<base::SharedMemory> MapSharedMemoryHandle(
erikchen328bf3f2015-10-24 00:46:54147 const base::SharedMemoryHandle& shm,
148 bool read_only) {
erikchenb82097cc2015-10-12 23:27:55149 if (!shm.IsValid()) {
150 LOG(ERROR) << "Invalid SharedMemoryHandle";
151 return nullptr;
152 }
153
154 size_t size;
155 if (!shm.GetSize(&size)) {
156 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
157 return nullptr;
158 }
159
danakj03de39b22016-04-23 04:21:09160 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:54161 new base::SharedMemory(shm, read_only));
erikchenb82097cc2015-10-12 23:27:55162 shared_memory->Map(size);
163 return shared_memory;
164}
165
166// This method maps the SharedMemoryHandle, checks the contents, and then
167// consumes a reference to the underlying Mach port.
168bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
169 const std::string& contents) {
danakj03de39b22016-04-23 04:21:09170 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:54171 MapSharedMemoryHandle(shm, false));
erikchenb82097cc2015-10-12 23:27:55172
173 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
174 LOG(ERROR) << "Shared Memory contents not equivalent";
175 return false;
176 }
177 return true;
178}
179
180// This method mmaps the FileDescriptor, checks the contents, and then munmaps
181// the FileDescriptor and closes the underlying fd.
182bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
183 const std::string& contents) {
184 base::ScopedFD fd_closer(file_descriptor.fd);
185 lseek(file_descriptor.fd, 0, SEEK_SET);
danakj03de39b22016-04-23 04:21:09186 std::unique_ptr<char, base::FreeDeleter> buffer(
erikchenb82097cc2015-10-12 23:27:55187 static_cast<char*>(malloc(contents.size())));
188 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
189 return false;
190
191 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
192 return result == 0;
193}
194
195// Open |fp| and populate it with |contents|.
196base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
197 const std::string& contents) {
198 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
199 base::ScopedFD fd_closer(fd);
200 if (fd <= 0) {
201 LOG(ERROR) << "Error opening file at: " << fp.value();
202 return base::FileDescriptor();
203 }
204
205 if (lseek(fd, 0, SEEK_SET) != 0) {
206 LOG(ERROR) << "Error changing offset";
207 return base::FileDescriptor();
208 }
209
210 if (write(fd, contents.c_str(), contents.size()) !=
211 static_cast<ssize_t>(contents.size())) {
212 LOG(ERROR) << "Error writing to file";
213 return base::FileDescriptor();
214 }
215
216 return base::FileDescriptor(fd_closer.release(), true);
217}
218
219// Maps both handles, then checks that their contents matches |contents|. Then
220// checks that changes to one are reflected in the other. Then consumes
221// references to both underlying Mach ports.
222bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
223 const base::SharedMemoryHandle& handle1,
224 const base::SharedMemoryHandle& handle2,
225 const std::string& contents) {
danakj03de39b22016-04-23 04:21:09226 std::unique_ptr<base::SharedMemory> shared_memory1(
erikchen328bf3f2015-10-24 00:46:54227 MapSharedMemoryHandle(handle1, false));
danakj03de39b22016-04-23 04:21:09228 std::unique_ptr<base::SharedMemory> shared_memory2(
erikchen328bf3f2015-10-24 00:46:54229 MapSharedMemoryHandle(handle2, false));
erikchenb82097cc2015-10-12 23:27:55230
231 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
232 0) {
233 LOG(ERROR) << "Incorrect contents in shared_memory1";
234 return false;
235 }
236
237 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
238 contents.size()) != 0) {
239 LOG(ERROR) << "Incorrect contents in shared_memory2";
240 return false;
241 }
242
243 // Updating shared_memory1 should update shared_memory2.
244 const char known_string[] = "string bean";
245 if (shared_memory1->mapped_size() < strlen(known_string) ||
246 shared_memory2->mapped_size() < strlen(known_string)) {
247 LOG(ERROR) << "Shared memory size is too small";
248 return false;
249 }
250 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
251
252 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
253 strlen(known_string)) != 0) {
254 LOG(ERROR) << "Incorrect contents in shared_memory2";
255 return false;
256 }
257
258 return true;
259}
260
261// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
262// whether the contents of the attached shared memory region matches |contents|.
263// Consumes a reference to the underlying Mach port.
264bool CheckContentsOfMessage1(const IPC::Message& message,
265 const std::string& contents) {
266 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
267 return CheckContentsOfSharedMemoryHandle(shm, contents);
268}
269
270// Once the test is finished, send a control message to the parent process with
271// the result. The message may require the runloop to be run before its
272// dispatched.
273void SendControlMessage(IPC::Sender* sender, bool success) {
274 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
275 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
276 message->WriteInt(result);
277 sender->Send(message);
278}
279
280// Records the most recently received brokerable attachment's id.
281class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
282 public:
283 void ReceivedBrokerableAttachmentWithId(
284 const IPC::BrokerableAttachment::AttachmentId& id) override {
285 id_ = id;
286 }
287 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
288
289 private:
290 IPC::BrokerableAttachment::AttachmentId id_;
291};
292
293// A broker which always sets the current process as the destination process
294// for attachments.
295class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
296 public:
297 MockBroker() {}
298 ~MockBroker() override {}
erikchena03dde6f2015-10-29 22:37:04299 bool SendAttachmentToProcess(
300 const scoped_refptr<IPC::BrokerableAttachment>& attachment,
301 base::ProcessId destination_process) override {
erikchenb82097cc2015-10-12 23:27:55302 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
303 attachment, base::Process::Current().Pid());
304 }
305};
306
307// Forwards all messages to |listener_|. Quits the message loop after a
308// message is received, or the channel has an error.
309class ProxyListener : public IPC::Listener {
310 public:
311 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
312 ~ProxyListener() override {}
313
314 // The reason for exiting the message loop.
315 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
316
317 bool OnMessageReceived(const IPC::Message& message) override {
318 bool result = false;
319 if (listener_)
320 result = listener_->OnMessageReceived(message);
321 reason_ = MESSAGE_RECEIVED;
322 messages_.push_back(message);
323 base::MessageLoop::current()->QuitNow();
324 return result;
325 }
326
327 void OnChannelError() override {
328 reason_ = CHANNEL_ERROR;
329 base::MessageLoop::current()->QuitNow();
330 }
331
332 void set_listener(IPC::Listener* listener) { listener_ = listener; }
333 Reason get_reason() { return reason_; }
334 IPC::Message get_first_message() {
335 DCHECK(!messages_.empty());
336 return messages_[0];
337 }
338 void pop_first_message() {
339 DCHECK(!messages_.empty());
340 messages_.erase(messages_.begin());
341 }
342 bool has_message() { return !messages_.empty(); }
343
344 private:
345 IPC::Listener* listener_;
346 Reason reason_;
347 std::vector<IPC::Message> messages_;
348};
349
350// Waits for a result to be sent over the channel. Quits the message loop
351// after a message is received, or the channel has an error.
352class ResultListener : public IPC::Listener {
353 public:
354 ResultListener() : result_(RESULT_UNKNOWN) {}
355 ~ResultListener() override {}
356
357 bool OnMessageReceived(const IPC::Message& message) override {
358 base::PickleIterator iter(message);
359
360 int result;
361 EXPECT_TRUE(iter.ReadInt(&result));
362 result_ = static_cast<TestResult>(result);
363 return true;
364 }
365
366 TestResult get_result() { return result_; }
367
368 private:
369 TestResult result_;
370};
371
372class MockPortProvider : public base::PortProvider {
373 public:
374 mach_port_t TaskForPid(base::ProcessHandle process) const override {
375 auto it = port_map_.find(process);
376 if (it != port_map_.end())
377 return it->second;
378 return MACH_PORT_NULL;
379 }
380
381 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
382 port_map_[process] = task_port;
erikchen7c556432015-11-11 22:07:27383 NotifyObservers(process);
erikchenb82097cc2015-10-12 23:27:55384 }
385
erikchen7c556432015-11-11 22:07:27386 void ClearPortMap() { port_map_.clear(); }
387
erikchenb82097cc2015-10-12 23:27:55388 private:
389 std::map<base::ProcessHandle, mach_port_t> port_map_;
390};
391
392// End-to-end tests for the attachment brokering process on Mac.
393// The parent process acts as an unprivileged process. The child process acts
394// as the privileged process.
395class IPCAttachmentBrokerMacTest : public IPCTestBase {
396 public:
397 IPCAttachmentBrokerMacTest() {}
398 ~IPCAttachmentBrokerMacTest() override {}
399
400 base::CommandLine MakeCmdLine(const std::string& procname) override {
401 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
402 // Pass the service name to the child process.
403 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
404 return command_line;
405 }
406
407 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
408 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
409 broker_.reset(broker);
410 }
411
erikchen24e44d32015-10-21 22:28:54412 // Mach Setup that needs to occur before child processes are forked.
413 void MachPreForkSetUp() {
414 service_name_ = IPC::CreateRandomServiceName();
415 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
416 }
417
418 // Mach Setup that needs to occur after child processes are forked.
419 void MachPostForkSetUp() {
420 client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
421 IPC::SendMachPort(
422 client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
423 }
424
erikchenb82097cc2015-10-12 23:27:55425 // Setup shared between tests.
426 void CommonSetUp(const char* name) {
erikchen90971902016-04-25 23:45:31427 PreConnectSetUp(name);
428 PostConnectSetUp();
429 }
430
431 // All of setup before the channel is connected.
432 void PreConnectSetUp(const char* name) {
erikchenb82097cc2015-10-12 23:27:55433 Init(name);
erikchen24e44d32015-10-21 22:28:54434 MachPreForkSetUp();
erikchenb82097cc2015-10-12 23:27:55435
436 if (!broker_.get())
437 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
438
erikchen94c9b702015-11-06 21:12:36439 broker_->AddObserver(&observer_, task_runner());
erikchenb82097cc2015-10-12 23:27:55440 CreateChannel(&proxy_listener_);
erikchen86662872016-02-17 04:09:14441 broker_->RegisterBrokerCommunicationChannel(channel());
erikchen90971902016-04-25 23:45:31442 }
443
444 // All of setup including the connection and everything after.
445 void PostConnectSetUp() {
erikchenb82097cc2015-10-12 23:27:55446 ASSERT_TRUE(ConnectChannel());
447 ASSERT_TRUE(StartClient());
448
erikchen24e44d32015-10-21 22:28:54449 MachPostForkSetUp();
erikchenb82097cc2015-10-12 23:27:55450 active_names_at_start_ = IPC::GetActiveNameCount();
451 get_proxy_listener()->set_listener(&result_listener_);
452 }
453
454 void CheckChildResult() {
455 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
456 get_proxy_listener()->get_reason());
457 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
458 }
459
460 void FinalCleanUp() {
461 // There should be no leaked names.
erikchene50acd882015-11-24 18:28:48462 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
463 base::TimeDelta::FromSeconds(10),
464 active_names_at_start_ == IPC::GetActiveNameCount());
erikchenb82097cc2015-10-12 23:27:55465 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
466
467 // Close the channel so the client's OnChannelError() gets fired.
468 channel()->Close();
469
470 EXPECT_TRUE(WaitForClientShutdown());
471 DestroyChannel();
472 broker_.reset();
473 }
474
475 // Teardown shared between most tests.
476 void CommonTearDown() {
477 CheckChildResult();
478 FinalCleanUp();
479 }
480
481 // Makes a SharedMemory region, fills it with |contents|, sends the handle
482 // over Chrome IPC, and unmaps the region.
483 void SendMessage1(const std::string& contents) {
danakj03de39b22016-04-23 04:21:09484 std::unique_ptr<base::SharedMemory> shared_memory(
485 MakeSharedMemory(contents));
erikchenb82097cc2015-10-12 23:27:55486 IPC::Message* message =
487 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
488 sender()->Send(message);
489 }
490
491 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
492 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
493 AttachmentBrokerObserver* get_observer() { return &observer_; }
494 ResultListener* get_result_listener() { return &result_listener_; }
495
erikchen24e44d32015-10-21 22:28:54496 protected:
497 // The number of active names immediately after set up.
498 mach_msg_type_number_t active_names_at_start_;
499
erikchenb82097cc2015-10-12 23:27:55500 private:
501 ProxyListener proxy_listener_;
danakj03de39b22016-04-23 04:21:09502 std::unique_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
erikchenb82097cc2015-10-12 23:27:55503 AttachmentBrokerObserver observer_;
504
505 // A port on which the main process listens for mach messages from the child
506 // process.
507 base::mac::ScopedMachReceiveRight server_port_;
508
509 // A port on which the child process listens for mach messages from the main
510 // process.
511 base::mac::ScopedMachSendRight client_port_;
512
erikchenb82097cc2015-10-12 23:27:55513 std::string service_name_;
514
515 ResultListener result_listener_;
516};
517
erikchenb82097cc2015-10-12 23:27:55518// These objects are globally accessible, and are expected to outlive all IPC
519// Channels.
520struct ChildProcessGlobals {
erikchenb82097cc2015-10-12 23:27:55521 MockPortProvider port_provider;
erikchen7c556432015-11-11 22:07:27522
523 // The broker must be destroyed before the port_provider, so that the broker
524 // gets a chance to unregister itself as an observer. This doesn't matter
525 // outside of tests, since neither port_provider nor broker will ever be
526 // destroyed.
danakj03de39b22016-04-23 04:21:09527 std::unique_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
erikchenb82097cc2015-10-12 23:27:55528 base::mac::ScopedMachSendRight server_task_port;
erikchene50acd882015-11-24 18:28:48529
530 // Total resident memory before running the message loop.
531 mach_vm_size_t initial_resident_size;
532
533 // Whether to emit log statements while processing messages.
534 bool message_logging;
erikchenb82097cc2015-10-12 23:27:55535};
536
erikchen7c556432015-11-11 22:07:27537using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
538 const IPC::Message& message,
539 ChildProcessGlobals* globals);
540
erikchenb82097cc2015-10-12 23:27:55541// Sets up the Mach communication ports with the server. Returns a set of
542// globals that must live at least as long as the test.
danakj03de39b22016-04-23 04:21:09543std::unique_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
erikchenb82097cc2015-10-12 23:27:55544 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
545 std::string service_name =
546 cmd_line.GetSwitchValueASCII(g_service_switch_name);
547 base::mac::ScopedMachSendRight server_port(
548 IPC::LookupServer(service_name.c_str()));
549 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
550
551 // Send the port that this process is listening on to the server.
markda902e182015-10-20 18:36:13552 IPC::SendMachPort(
553 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
erikchenb82097cc2015-10-12 23:27:55554
555 // Receive the task port of the server process.
556 base::mac::ScopedMachSendRight server_task_port(
markda902e182015-10-20 18:36:13557 IPC::ReceiveMachPort(client_port.get()));
erikchenb82097cc2015-10-12 23:27:55558
danakj03de39b22016-04-23 04:21:09559 std::unique_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
erikchend8a3d9022015-10-22 20:02:02560 globals->broker.reset(
561 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
markda902e182015-10-20 18:36:13562 globals->port_provider.InsertEntry(getppid(), server_task_port.get());
erikchenb82097cc2015-10-12 23:27:55563 globals->server_task_port.reset(server_task_port.release());
erikchene50acd882015-11-24 18:28:48564 globals->message_logging = true;
erikchenb82097cc2015-10-12 23:27:55565 return globals;
566}
567
568int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
569 const char* channel_name) {
570 LOG(INFO) << "Privileged process start.";
danakj03de39b22016-04-23 04:21:09571 std::unique_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
erikchenb82097cc2015-10-12 23:27:55572
573 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
574
575 base::MessageLoopForIO main_message_loop;
576 ProxyListener listener;
577
danakj03de39b22016-04-23 04:21:09578 std::unique_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
erikchenb82097cc2015-10-12 23:27:55579 IPCTestBase::GetChannelName(channel_name), &listener));
erikchena91d05132016-03-21 23:19:40580 globals->broker->RegisterCommunicationChannel(channel.get(), nullptr);
erikchenb82097cc2015-10-12 23:27:55581 CHECK(channel->Connect());
582
erikchene50acd882015-11-24 18:28:48583 globals->initial_resident_size = GetResidentSize();
584
erikchenb82097cc2015-10-12 23:27:55585 while (true) {
erikchene50acd882015-11-24 18:28:48586 if (globals->message_logging)
587 LOG(INFO) << "Privileged process spinning run loop.";
fdoray8e32586852016-06-22 19:56:16588 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55589 ProxyListener::Reason reason = listener.get_reason();
590 if (reason == ProxyListener::CHANNEL_ERROR)
591 break;
592
593 while (listener.has_message()) {
erikchene50acd882015-11-24 18:28:48594 if (globals->message_logging)
595 LOG(INFO) << "Privileged process running callback.";
erikchen7c556432015-11-11 22:07:27596 callback(channel.get(), listener.get_first_message(), globals.get());
erikchene50acd882015-11-24 18:28:48597 if (globals->message_logging)
598 LOG(INFO) << "Privileged process finishing callback.";
erikchenb82097cc2015-10-12 23:27:55599 listener.pop_first_message();
600 }
601 }
602
603 if (active_names_at_start != IPC::GetActiveNameCount()) {
604 LOG(INFO) << "Memory leak!.";
605 }
606 LOG(INFO) << "Privileged process end.";
607 return 0;
608}
609
610// An unprivileged process makes a shared memory region, and writes a string to
611// it. The SharedMemoryHandle is sent to the privileged process using Chrome
612// IPC. The privileged process checks that it received the same memory region.
613TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
614 CommonSetUp("SendSharedMemoryHandle");
615
616 SendMessage1(kDataBuffer1);
fdoray8e32586852016-06-22 19:56:16617 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55618 CommonTearDown();
619}
620
621void SendSharedMemoryHandleCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27622 const IPC::Message& message,
623 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55624 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
625 SendControlMessage(sender, success);
626}
627
628MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
629 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
630 "SendSharedMemoryHandle");
631}
632
633// Similar to SendSharedMemoryHandle, but sends a very long shared memory
634// region.
635TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
636 CommonSetUp("SendSharedMemoryHandleLong");
637
638 std::string buffer(1 << 23, 'a');
639 SendMessage1(buffer);
fdoray8e32586852016-06-22 19:56:16640 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55641 CommonTearDown();
642}
643
644void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27645 const IPC::Message& message,
646 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55647 std::string buffer(1 << 23, 'a');
648 bool success = CheckContentsOfMessage1(message, buffer);
649 SendControlMessage(sender, success);
650}
651
652MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
653 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
654 "SendSharedMemoryHandleLong");
655}
656
657// Similar to SendSharedMemoryHandle, but sends two different shared memory
658// regions in two messages.
659TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
660 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
661
662 SendMessage1(kDataBuffer1);
663 SendMessage1(kDataBuffer2);
fdoray8e32586852016-06-22 19:56:16664 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55665 CommonTearDown();
666}
667
668void SendTwoMessagesDifferentSharedMemoryHandleCallback(
669 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27670 const IPC::Message& message,
671 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55672 static int count = 0;
673 static bool success = true;
674 ++count;
675 if (count == 1) {
676 success &= CheckContentsOfMessage1(message, kDataBuffer1);
677 } else if (count == 2) {
678 success &= CheckContentsOfMessage1(message, kDataBuffer2);
679 SendControlMessage(sender, success);
680 }
681}
682
683MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
684 return CommonPrivilegedProcessMain(
685 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
686 "SendTwoMessagesDifferentSharedMemoryHandle");
687}
688
689// Similar to SendSharedMemoryHandle, but sends the same shared memory region in
690// two messages.
691TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
692 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
693
694 {
danakj03de39b22016-04-23 04:21:09695 std::unique_ptr<base::SharedMemory> shared_memory(
erikchenb82097cc2015-10-12 23:27:55696 MakeSharedMemory(kDataBuffer1));
697
698 for (int i = 0; i < 2; ++i) {
699 IPC::Message* message =
700 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
701 sender()->Send(message);
702 }
703 }
704
fdoray8e32586852016-06-22 19:56:16705 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55706 CommonTearDown();
707}
708
709void SendTwoMessagesSameSharedMemoryHandleCallback(
710 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27711 const IPC::Message& message,
712 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55713 static int count = 0;
714 static base::SharedMemoryHandle handle1;
715 ++count;
716
717 if (count == 1) {
718 handle1 = GetSharedMemoryHandleFromMsg1(message);
719 } else if (count == 2) {
720 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
721
722 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
723 handle1, handle2, kDataBuffer1);
724 SendControlMessage(sender, success);
725 }
726}
727
728MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
729 return CommonPrivilegedProcessMain(
730 &SendTwoMessagesSameSharedMemoryHandleCallback,
731 "SendTwoMessagesSameSharedMemoryHandle");
732}
733
734// Similar to SendSharedMemoryHandle, but sends one message with two different
735// memory regions.
736TEST_F(IPCAttachmentBrokerMacTest,
737 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
738 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
739
740 {
danakj03de39b22016-04-23 04:21:09741 std::unique_ptr<base::SharedMemory> shared_memory1(
erikchenb82097cc2015-10-12 23:27:55742 MakeSharedMemory(kDataBuffer1));
danakj03de39b22016-04-23 04:21:09743 std::unique_ptr<base::SharedMemory> shared_memory2(
erikchenb82097cc2015-10-12 23:27:55744 MakeSharedMemory(kDataBuffer2));
745 IPC::Message* message = new TestSharedMemoryHandleMsg2(
746 shared_memory1->handle(), shared_memory2->handle());
747 sender()->Send(message);
748 }
fdoray8e32586852016-06-22 19:56:16749 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55750 CommonTearDown();
751}
752
753void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
754 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27755 const IPC::Message& message,
756 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55757 base::SharedMemoryHandle handle1;
758 base::SharedMemoryHandle handle2;
759 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
760 LOG(ERROR) << "Failed to deserialize message.";
761 SendControlMessage(sender, false);
762 return;
763 }
764
765 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
766 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
767 SendControlMessage(sender, success);
768}
769
770MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
771 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
772 return CommonPrivilegedProcessMain(
773 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
774 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
775}
776
777// Similar to SendSharedMemoryHandle, but sends one message that contains the
778// same memory region twice.
779TEST_F(IPCAttachmentBrokerMacTest,
780 SendOneMessageWithTwoSameSharedMemoryHandles) {
781 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
782
783 {
danakj03de39b22016-04-23 04:21:09784 std::unique_ptr<base::SharedMemory> shared_memory(
erikchenb82097cc2015-10-12 23:27:55785 MakeSharedMemory(kDataBuffer1));
786 IPC::Message* message = new TestSharedMemoryHandleMsg2(
787 shared_memory->handle(), shared_memory->handle());
788 sender()->Send(message);
789 }
fdoray8e32586852016-06-22 19:56:16790 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55791 CommonTearDown();
792}
793
794void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
795 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27796 const IPC::Message& message,
797 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55798 base::SharedMemoryHandle handle1;
799 base::SharedMemoryHandle handle2;
800 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
801 LOG(ERROR) << "Failed to deserialize message.";
802 SendControlMessage(sender, false);
803 return;
804 }
805
806 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
807 handle1, handle2, kDataBuffer1);
808 SendControlMessage(sender, success);
809}
810
811MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
812 SendOneMessageWithTwoSameSharedMemoryHandles) {
813 return CommonPrivilegedProcessMain(
814 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
815 "SendOneMessageWithTwoSameSharedMemoryHandles");
816}
817
818// Sends one message with two Posix FDs and two Mach ports.
819TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
820 base::ScopedTempDir temp_dir;
821 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
822 base::FilePath fp1, fp2;
823 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
824 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
825
826 CommonSetUp("SendPosixFDAndMachPort");
827
828 {
danakj03de39b22016-04-23 04:21:09829 std::unique_ptr<base::SharedMemory> shared_memory1(
erikchenb82097cc2015-10-12 23:27:55830 MakeSharedMemory(kDataBuffer1));
danakj03de39b22016-04-23 04:21:09831 std::unique_ptr<base::SharedMemory> shared_memory2(
erikchenb82097cc2015-10-12 23:27:55832 MakeSharedMemory(kDataBuffer2));
833
834 base::FileDescriptor file_descriptor1(
835 MakeFileDescriptor(fp1, kDataBuffer3));
836 base::FileDescriptor file_descriptor2(
837 MakeFileDescriptor(fp2, kDataBuffer4));
838
839 IPC::Message* message = new TestSharedMemoryHandleMsg3(
840 file_descriptor1, shared_memory1->handle(), file_descriptor2,
841 shared_memory2->handle());
842 sender()->Send(message);
843 }
844
fdoray8e32586852016-06-22 19:56:16845 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55846 CommonTearDown();
847}
848
849void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27850 const IPC::Message& message,
851 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55852 TestSharedMemoryHandleMsg3::Schema::Param p;
853 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
854 LOG(ERROR) << "Failed to deserialize message.";
855 SendControlMessage(sender, false);
856 return;
857 }
858
tzik55e3e4d2016-03-08 05:47:44859 base::SharedMemoryHandle handle1 = std::get<1>(p);
860 base::SharedMemoryHandle handle2 = std::get<3>(p);
erikchenb82097cc2015-10-12 23:27:55861 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
862 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
863 if (!success1)
864 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
865
866 bool success2 =
tzik55e3e4d2016-03-08 05:47:44867 CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) &&
868 CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4);
erikchenb82097cc2015-10-12 23:27:55869 if (!success2)
870 LOG(ERROR) << "FileDescriptors have wrong contents.";
871
872 SendControlMessage(sender, success1 && success2);
873}
874
875MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
876 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
877 "SendPosixFDAndMachPort");
878}
879
880// Similar to SendHandle, except the attachment's destination process is this
881// process. This is an unrealistic scenario, but simulates an unprivileged
882// process sending an attachment to another unprivileged process.
883TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
884 SetBroker(new MockBroker);
erikchen90971902016-04-25 23:45:31885 PreConnectSetUp("SendSharedMemoryHandleToSelf");
erikchenb82097cc2015-10-12 23:27:55886 // Technically, the channel is an endpoint, but we need the proxy listener to
887 // receive the messages so that it can quit the message loop.
888 channel()->SetAttachmentBrokerEndpoint(false);
erikchen90971902016-04-25 23:45:31889 PostConnectSetUp();
erikchenb82097cc2015-10-12 23:27:55890 get_proxy_listener()->set_listener(get_broker());
891
892 {
danakj03de39b22016-04-23 04:21:09893 std::unique_ptr<base::SharedMemory> shared_memory(
erikchenb82097cc2015-10-12 23:27:55894 MakeSharedMemory(kDataBuffer1));
895 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
896 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
897
898 IPC::Message* message =
899 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
900 sender()->Send(message);
erikchen94c9b702015-11-06 21:12:36901
902 // Wait until the child process has sent this process a message.
fdoray8e32586852016-06-22 19:56:16903 base::RunLoop().Run();
erikchenb82097cc2015-10-12 23:27:55904
erikchen94c9b702015-11-06 21:12:36905 // Wait for any asynchronous activity to complete.
fdoray8e32586852016-06-22 19:56:16906 base::RunLoop().RunUntilIdle();
erikchen94c9b702015-11-06 21:12:36907
erikchenb82097cc2015-10-12 23:27:55908 // Get the received attachment.
909 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
erikchen94c9b702015-11-06 21:12:36910 ASSERT_TRUE(id);
erikchenb82097cc2015-10-12 23:27:55911 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
912 get_broker()->GetAttachmentWithId(*id, &received_attachment);
913 ASSERT_NE(received_attachment.get(), nullptr);
914
915 // Check that it's has the same name, but that the ref count has increased.
916 base::mac::ScopedMachSendRight memory_object(
917 GetMachPortFromBrokeredAttachment(received_attachment));
918 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
919 EXPECT_EQ(ref_count + 1,
920 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
921 MACH_PORT_RIGHT_SEND));
922 }
923
924 FinalCleanUp();
925}
926
927void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27928 const IPC::Message&,
929 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55930 // Do nothing special. The default behavior already runs the
931 // AttachmentBrokerPrivilegedMac.
932}
933
934MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
935 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
936 "SendSharedMemoryHandleToSelf");
937}
938
erikchen24e44d32015-10-21 22:28:54939// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
940// Channel.
941TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
942 Init("SendSharedMemoryHandleChannelProxy");
943 MachPreForkSetUp();
944
945 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
erikchen94c9b702015-11-06 21:12:36946 get_broker()->AddObserver(get_observer(), task_runner());
erikchen24e44d32015-10-21 22:28:54947
danakj03de39b22016-04-23 04:21:09948 std::unique_ptr<base::Thread> thread(
erikchen24e44d32015-10-21 22:28:54949 new base::Thread("ChannelProxyTestServerThread"));
950 base::Thread::Options options;
951 options.message_loop_type = base::MessageLoop::TYPE_IO;
952 thread->StartWithOptions(options);
953
erikchen90971902016-04-25 23:45:31954 set_channel_proxy(std::unique_ptr<IPC::ChannelProxy>(new IPC::ChannelProxy(
955 get_proxy_listener(), thread->task_runner().get())));
erikchen86662872016-02-17 04:09:14956 get_broker()->RegisterBrokerCommunicationChannel(channel_proxy());
erikchen90971902016-04-25 23:45:31957 channel_proxy()->Init(
958 CreateChannelFactory(GetTestChannelHandle(), thread->task_runner().get()),
959 true);
erikchen24e44d32015-10-21 22:28:54960
961 ASSERT_TRUE(StartClient());
962
963 MachPostForkSetUp();
964 active_names_at_start_ = IPC::GetActiveNameCount();
965 get_proxy_listener()->set_listener(get_result_listener());
966
967 SendMessage1(kDataBuffer1);
fdoray8e32586852016-06-22 19:56:16968 base::RunLoop().Run();
erikchen24e44d32015-10-21 22:28:54969
970 CheckChildResult();
971
972 // There should be no leaked names.
973 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
974
975 // Close the channel so the client's OnChannelError() gets fired.
976 channel_proxy()->Close();
977
978 EXPECT_TRUE(WaitForClientShutdown());
979 DestroyChannelProxy();
980}
981
982void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27983 const IPC::Message& message,
984 ChildProcessGlobals* globals) {
erikchen24e44d32015-10-21 22:28:54985 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
986 SendControlMessage(sender, success);
987}
988
989MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
990 return CommonPrivilegedProcessMain(
991 &SendSharedMemoryHandleChannelProxyCallback,
992 "SendSharedMemoryHandleChannelProxy");
993}
994
erikchen328bf3f2015-10-24 00:46:54995// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
996// ShareToProcess().
997TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
erikchen328bf3f2015-10-24 00:46:54998 CommonSetUp("ShareToProcess");
999
1000 {
danakj03de39b22016-04-23 04:21:091001 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:541002 MakeSharedMemory(kDataBuffer1));
1003 base::SharedMemoryHandle new_handle;
1004 ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
1005 IPC::Message* message =
1006 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1007 sender()->Send(message);
1008 }
1009
fdoray8e32586852016-06-22 19:56:161010 base::RunLoop().Run();
erikchen328bf3f2015-10-24 00:46:541011 CommonTearDown();
1012}
1013
erikchen7c556432015-11-11 22:07:271014void ShareToProcessCallback(IPC::Sender* sender,
1015 const IPC::Message& message,
1016 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541017 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
1018 SendControlMessage(sender, success);
1019}
1020
1021MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
1022 return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
1023}
1024
1025// Similar to ShareToProcess, but instead shares the memory object only with
1026// read permissions.
1027TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
erikchen328bf3f2015-10-24 00:46:541028 CommonSetUp("ShareReadOnlyToProcess");
1029
1030 {
danakj03de39b22016-04-23 04:21:091031 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:541032 MakeSharedMemory(kDataBuffer1));
1033 base::SharedMemoryHandle new_handle;
1034 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
1035 IPC::Message* message =
1036 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1037 sender()->Send(message);
1038 }
1039
fdoray8e32586852016-06-22 19:56:161040 base::RunLoop().Run();
erikchen328bf3f2015-10-24 00:46:541041 CommonTearDown();
1042}
1043
1044void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:271045 const IPC::Message& message,
1046 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541047 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1048
1049 // Try to map the memory as writable.
danakj03de39b22016-04-23 04:21:091050 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:541051 MapSharedMemoryHandle(shm, false));
1052 ASSERT_EQ(nullptr, shared_memory->memory());
1053
1054 // Now try as read-only.
danakj03de39b22016-04-23 04:21:091055 std::unique_ptr<base::SharedMemory> shared_memory2(
erikchen328bf3f2015-10-24 00:46:541056 MapSharedMemoryHandle(shm.Duplicate(), true));
1057 int current_prot, max_prot;
1058 ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
1059 shared_memory2->mapped_size(),
1060 &current_prot, &max_prot));
1061 ASSERT_EQ(VM_PROT_READ, current_prot);
1062 ASSERT_EQ(VM_PROT_READ, max_prot);
1063
1064 bool success =
1065 memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
1066 SendControlMessage(sender, success);
1067}
1068
1069MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
1070 return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
1071 "ShareReadOnlyToProcess");
1072}
1073
erikchen7c556432015-11-11 22:07:271074// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
1075// not have the task port for the parent process.
1076TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
erikchen7c556432015-11-11 22:07:271077 SetBroker(new MockBroker);
erikchen90971902016-04-25 23:45:311078 PreConnectSetUp("SendSharedMemoryHandleToSelfDelayedPort");
erikchen7c556432015-11-11 22:07:271079 // Technically, the channel is an endpoint, but we need the proxy listener to
1080 // receive the messages so that it can quit the message loop.
1081 channel()->SetAttachmentBrokerEndpoint(false);
erikchen90971902016-04-25 23:45:311082 PostConnectSetUp();
erikchen7c556432015-11-11 22:07:271083 get_proxy_listener()->set_listener(get_broker());
1084
1085 {
danakj03de39b22016-04-23 04:21:091086 std::unique_ptr<base::SharedMemory> shared_memory(
erikchen7c556432015-11-11 22:07:271087 MakeSharedMemory(kDataBuffer1));
1088 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
1089 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
1090
1091 std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
1092 const int kMessagesToTest = 3;
1093 for (int i = 0; i < kMessagesToTest; ++i) {
1094 base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
1095 ids.push_back(
1096 IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
1097 IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
1098 h.GetMemoryObject(), getpid(), ids[i]);
1099 sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
1100
1101 // Send a dummy message, which will trigger the callback handler in the
1102 // child process.
1103 sender()->Send(new TestSharedMemoryHandleMsg4(1));
1104 }
1105
1106 int received_message_count = 0;
1107 while (received_message_count < kMessagesToTest) {
1108 // Wait until the child process has sent this process a message.
fdoray8e32586852016-06-22 19:56:161109 base::RunLoop().Run();
erikchen7c556432015-11-11 22:07:271110
1111 // Wait for any asynchronous activity to complete.
fdoray8e32586852016-06-22 19:56:161112 base::RunLoop().RunUntilIdle();
erikchen7c556432015-11-11 22:07:271113
1114 while (get_proxy_listener()->has_message()) {
1115 get_proxy_listener()->pop_first_message();
1116 received_message_count++;
1117 }
1118 }
1119
1120 for (int i = 0; i < kMessagesToTest; ++i) {
1121 IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
1122 ASSERT_TRUE(id);
1123 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
1124 get_broker()->GetAttachmentWithId(*id, &received_attachment);
1125 ASSERT_NE(received_attachment.get(), nullptr);
1126
1127 base::mac::ScopedMachSendRight memory_object(
1128 GetMachPortFromBrokeredAttachment(received_attachment));
1129 ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
1130 }
1131
1132 // Check that the ref count hasn't changed.
1133 EXPECT_EQ(ref_count,
1134 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
1135 MACH_PORT_RIGHT_SEND));
1136 }
1137
1138 FinalCleanUp();
1139}
1140
1141void SendSharedMemoryHandleToSelfDelayedPortCallback(
1142 IPC::Sender* sender,
1143 const IPC::Message& message,
1144 ChildProcessGlobals* globals) {
1145 static int i = 0;
1146 static base::ProcessId pid = message.get_sender_pid();
1147 static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
1148 ++i;
1149
1150 if (i == 1) {
1151 // Pretend to not have the task port for the parent.
1152 globals->port_provider.ClearPortMap();
1153 } else if (i == 2) {
1154 // Intentionally do nothing.
1155 } else if (i == 3) {
1156 // Setting the task port should trigger callbacks, eventually resulting in
1157 // multiple attachment broker messages.
1158 globals->port_provider.InsertEntry(pid, task_port);
1159 }
1160}
1161
1162MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
1163 return CommonPrivilegedProcessMain(
1164 &SendSharedMemoryHandleToSelfDelayedPortCallback,
1165 "SendSharedMemoryHandleToSelfDelayedPort");
1166}
1167
erikchene50acd882015-11-24 18:28:481168// Tests the memory usage characteristics of attachment brokering a single large
1169// message. This test has the *potential* to be flaky, since it compares
1170// resident memory at different points in time, and that measurement is
1171// non-deterministic.
1172TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) {
erikchene50acd882015-11-24 18:28:481173 CommonSetUp("MemoryUsageLargeMessage");
1174
1175 std::string test_string(g_large_message_size, 'a');
1176 SendMessage1(test_string);
fdoray8e32586852016-06-22 19:56:161177 base::RunLoop().Run();
erikchene50acd882015-11-24 18:28:481178 CommonTearDown();
1179}
1180
1181void MemoryUsageLargeMessageCallback(IPC::Sender* sender,
1182 const IPC::Message& message,
1183 ChildProcessGlobals* globals) {
1184 EXPECT_LE(GetResidentSize(),
1185 globals->initial_resident_size + g_expected_memory_increase);
1186
1187 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
danakj03de39b22016-04-23 04:21:091188 std::unique_ptr<base::SharedMemory> shared_memory(
erikchene50acd882015-11-24 18:28:481189 MapSharedMemoryHandle(shm, false));
1190 EXPECT_LE(GetResidentSize(),
1191 globals->initial_resident_size + g_expected_memory_increase);
1192
1193 char* addr = static_cast<char*>(shared_memory->memory());
1194 for (size_t i = 0; i < g_large_message_size; i += 1024) {
1195 addr[i] = 'a';
1196 }
1197 EXPECT_GE(GetResidentSize(),
1198 globals->initial_resident_size + g_large_message_size);
1199
1200 shared_memory.reset();
1201#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
1202 !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
1203 !defined(UNDEFINED_SANITIZER)
1204 // Under a sanitizer build, releasing memory does not necessarily reduce the
1205 // amount of resident memory.
1206 EXPECT_LE(GetResidentSize(),
1207 globals->initial_resident_size + g_expected_memory_increase);
1208#endif
1209
1210 SendControlMessage(sender, true);
1211}
1212
1213MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) {
1214 return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback,
1215 "MemoryUsageLargeMessage");
1216}
1217
1218// Tests the memory usage characteristics of attachment brokering many small
1219// messages. This test has the *potential* to be flaky, since it compares
1220// resident memory at different points in time, and that measurement is
1221// non-deterministic.
1222TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) {
erikchene50acd882015-11-24 18:28:481223 CommonSetUp("MemoryUsageManyMessages");
1224
1225 for (int i = 0; i < g_large_message_count; ++i) {
1226 std::string message = base::IntToString(i);
1227 message += '\0';
1228 size_t end = message.size();
1229 message.resize(g_medium_message_size);
1230 std::fill(message.begin() + end, message.end(), 'a');
1231 SendMessage1(message);
1232
fdoray8e32586852016-06-22 19:56:161233 base::RunLoop().RunUntilIdle();
erikchene50acd882015-11-24 18:28:481234 }
1235
1236 if (get_result_listener()->get_result() == RESULT_UNKNOWN)
fdoray8e32586852016-06-22 19:56:161237 base::RunLoop().Run();
erikchene50acd882015-11-24 18:28:481238
1239 CommonTearDown();
1240}
1241
1242void MemoryUsageManyMessagesCallback(IPC::Sender* sender,
1243 const IPC::Message& message,
1244 ChildProcessGlobals* globals) {
1245 static int message_index = 0;
1246
1247 {
1248 // Map the shared memory, and make sure that its pages are counting towards
1249 // resident size.
1250 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
danakj03de39b22016-04-23 04:21:091251 std::unique_ptr<base::SharedMemory> shared_memory(
erikchene50acd882015-11-24 18:28:481252 MapSharedMemoryHandle(shm, false));
1253
1254 char* addr = static_cast<char*>(shared_memory->memory());
1255 std::string message_string(addr);
1256 int message_int;
1257 ASSERT_TRUE(base::StringToInt(message_string, &message_int));
1258 ASSERT_EQ(message_index, message_int);
1259 for (size_t i = 0; i < g_medium_message_size; i += 1024) {
1260 addr[i] = 'a';
1261 }
1262 }
1263
1264 ++message_index;
1265
1266 if (message_index == 1) {
1267 // Disable message logging, since it significantly contributes towards total
1268 // memory usage.
1269 LOG(INFO) << "Disable privileged process message logging.";
1270 globals->message_logging = false;
1271 }
1272
1273 if (message_index == g_large_message_count) {
1274 size_t memory_increase_kb =
1275 (GetResidentSize() - globals->initial_resident_size) / 1024;
1276 LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb;
1277
1278#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
1279 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
1280 defined(UNDEFINED_SANITIZER)
1281 // Under a sanitizer build, releasing memory does not necessarily reduce the
1282 // amount of resident memory.
1283 bool success = true;
1284#else
1285 // The total increase in resident size should be less than 1MB. The exact
1286 // amount is not deterministic.
1287 bool success = memory_increase_kb < 1024;
1288#endif
1289
1290 SendControlMessage(sender, success);
1291 }
1292}
1293
1294MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) {
1295 return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback,
1296 "MemoryUsageManyMessages");
1297}
1298
erikchenb82097cc2015-10-12 23:27:551299} // namespace