blob: 61d41d78300ce805b6881ff11dd11bb0588df038 [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
tzik55e3e4d2016-03-08 05:47:4412#include <tuple>
13
erikchenb82097cc2015-10-12 23:27:5514#include "base/command_line.h"
15#include "base/files/file_util.h"
16#include "base/files/scoped_file.h"
17#include "base/files/scoped_temp_dir.h"
erikchen328bf3f2015-10-24 00:46:5418#include "base/mac/mac_util.h"
erikchene50acd882015-11-24 18:28:4819#include "base/mac/mach_logging.h"
dchengdb5935f2016-03-26 00:16:2720#include "base/memory/free_deleter.h"
erikchenb82097cc2015-10-12 23:27:5521#include "base/memory/scoped_ptr.h"
22#include "base/memory/shared_memory.h"
erikchene50acd882015-11-24 18:28:4823#include "base/strings/string_number_conversions.h"
24#include "base/synchronization/spin_wait.h"
25#include "base/time/time.h"
erikchen7c556432015-11-11 22:07:2726#include "ipc/attachment_broker_messages.h"
erikchenb82097cc2015-10-12 23:27:5527#include "ipc/attachment_broker_privileged_mac.h"
28#include "ipc/attachment_broker_unprivileged_mac.h"
29#include "ipc/ipc_listener.h"
30#include "ipc/ipc_message.h"
31#include "ipc/ipc_test_base.h"
32#include "ipc/ipc_test_messages.h"
33#include "ipc/test_util_mac.h"
34
35namespace {
36
37const char kDataBuffer1[] = "This is some test data to write to the file.";
38const char kDataBuffer2[] = "The lazy dog and a fox.";
39const char kDataBuffer3[] = "Two green bears but not a potato.";
40const char kDataBuffer4[] = "Red potato is best potato.";
41const std::string g_service_switch_name = "service_name";
erikchene50acd882015-11-24 18:28:4842const size_t g_large_message_size = 8 * 1024 * 1024;
43const int g_large_message_count = 1000;
44const size_t g_medium_message_size = 512 * 1024;
45
46// Running the message loop is expected to increase the number of resident
47// pages. The exact amount is non-deterministic, but for a simple test suite
48// like this one, the increase is expected to be less than 1 MB.
49const size_t g_expected_memory_increase = 1024 * 1024;
erikchenb82097cc2015-10-12 23:27:5550
51enum TestResult {
52 RESULT_UNKNOWN,
53 RESULT_SUCCESS,
54 RESULT_FAILURE,
55};
56
erikchene50acd882015-11-24 18:28:4857mach_vm_size_t GetResidentSize() {
58 task_basic_info_64 info;
59 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
60 kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
61 reinterpret_cast<task_info_t>(&info), &count);
62 MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size.";
63
64 return info.resident_size;
65}
66
erikchenb82097cc2015-10-12 23:27:5567base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
68 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
69 if (attachment->GetType() !=
70 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
71 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
72 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
73 }
74
75 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
76 LOG(INFO) << "Brokerable type not MACH_PORT.";
77 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
78 }
79
80 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
81 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
erikchen8a6f3f4e2016-01-06 22:04:4382 base::mac::ScopedMachSendRight send_right(
erikchenb82097cc2015-10-12 23:27:5583 received_mach_port_attachment->get_mach_port());
erikchen8a6f3f4e2016-01-06 22:04:4384 received_mach_port_attachment->reset_mach_port_ownership();
85 return send_right;
erikchenb82097cc2015-10-12 23:27:5586}
87
88// Makes a Mach port backed SharedMemory region and fills it with |contents|.
89scoped_ptr<base::SharedMemory> MakeSharedMemory(const std::string& contents) {
90 base::SharedMemoryHandle shm(contents.size());
91 if (!shm.IsValid()) {
92 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
93 return nullptr;
94 }
95 scoped_ptr<base::SharedMemory> shared_memory(
96 new base::SharedMemory(shm, false));
97 shared_memory->Map(contents.size());
98 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
99 return shared_memory;
100}
101
102// |message| must be deserializable as a TestSharedMemoryHandleMsg1.
103base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
104 const IPC::Message& message) {
105 // Expect a message with a brokered attachment.
106 if (!message.HasBrokerableAttachments()) {
107 LOG(ERROR) << "Message missing brokerable attachment.";
108 return base::SharedMemoryHandle();
109 }
110
111 TestSharedMemoryHandleMsg1::Schema::Param p;
112 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
113 LOG(ERROR) << "Failed to deserialize message.";
114 return base::SharedMemoryHandle();
115 }
116
tzik55e3e4d2016-03-08 05:47:44117 return std::get<1>(p);
erikchenb82097cc2015-10-12 23:27:55118}
119
120// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
121// whether deserialization was successful. |handle1| and |handle2| are output
122// variables populated on success.
123bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
124 base::SharedMemoryHandle* handle1,
125 base::SharedMemoryHandle* handle2) {
126 // Expect a message with a brokered attachment.
127 if (!message.HasBrokerableAttachments()) {
128 LOG(ERROR) << "Message missing brokerable attachment.";
129 return false;
130 }
131
132 TestSharedMemoryHandleMsg2::Schema::Param p;
133 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
134 LOG(ERROR) << "Failed to deserialize message.";
135 return false;
136 }
137
tzik55e3e4d2016-03-08 05:47:44138 *handle1 = std::get<0>(p);
139 *handle2 = std::get<1>(p);
erikchenb82097cc2015-10-12 23:27:55140 return true;
141}
142
143// Returns |nullptr| on error.
144scoped_ptr<base::SharedMemory> MapSharedMemoryHandle(
erikchen328bf3f2015-10-24 00:46:54145 const base::SharedMemoryHandle& shm,
146 bool read_only) {
erikchenb82097cc2015-10-12 23:27:55147 if (!shm.IsValid()) {
148 LOG(ERROR) << "Invalid SharedMemoryHandle";
149 return nullptr;
150 }
151
152 size_t size;
153 if (!shm.GetSize(&size)) {
154 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
155 return nullptr;
156 }
157
158 scoped_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:54159 new base::SharedMemory(shm, read_only));
erikchenb82097cc2015-10-12 23:27:55160 shared_memory->Map(size);
161 return shared_memory;
162}
163
164// This method maps the SharedMemoryHandle, checks the contents, and then
165// consumes a reference to the underlying Mach port.
166bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
167 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54168 scoped_ptr<base::SharedMemory> shared_memory(
169 MapSharedMemoryHandle(shm, false));
erikchenb82097cc2015-10-12 23:27:55170
171 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
172 LOG(ERROR) << "Shared Memory contents not equivalent";
173 return false;
174 }
175 return true;
176}
177
178// This method mmaps the FileDescriptor, checks the contents, and then munmaps
179// the FileDescriptor and closes the underlying fd.
180bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
181 const std::string& contents) {
182 base::ScopedFD fd_closer(file_descriptor.fd);
183 lseek(file_descriptor.fd, 0, SEEK_SET);
184 scoped_ptr<char, base::FreeDeleter> buffer(
185 static_cast<char*>(malloc(contents.size())));
186 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
187 return false;
188
189 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
190 return result == 0;
191}
192
193// Open |fp| and populate it with |contents|.
194base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
195 const std::string& contents) {
196 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
197 base::ScopedFD fd_closer(fd);
198 if (fd <= 0) {
199 LOG(ERROR) << "Error opening file at: " << fp.value();
200 return base::FileDescriptor();
201 }
202
203 if (lseek(fd, 0, SEEK_SET) != 0) {
204 LOG(ERROR) << "Error changing offset";
205 return base::FileDescriptor();
206 }
207
208 if (write(fd, contents.c_str(), contents.size()) !=
209 static_cast<ssize_t>(contents.size())) {
210 LOG(ERROR) << "Error writing to file";
211 return base::FileDescriptor();
212 }
213
214 return base::FileDescriptor(fd_closer.release(), true);
215}
216
217// Maps both handles, then checks that their contents matches |contents|. Then
218// checks that changes to one are reflected in the other. Then consumes
219// references to both underlying Mach ports.
220bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
221 const base::SharedMemoryHandle& handle1,
222 const base::SharedMemoryHandle& handle2,
223 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54224 scoped_ptr<base::SharedMemory> shared_memory1(
225 MapSharedMemoryHandle(handle1, false));
226 scoped_ptr<base::SharedMemory> shared_memory2(
227 MapSharedMemoryHandle(handle2, false));
erikchenb82097cc2015-10-12 23:27:55228
229 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
230 0) {
231 LOG(ERROR) << "Incorrect contents in shared_memory1";
232 return false;
233 }
234
235 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
236 contents.size()) != 0) {
237 LOG(ERROR) << "Incorrect contents in shared_memory2";
238 return false;
239 }
240
241 // Updating shared_memory1 should update shared_memory2.
242 const char known_string[] = "string bean";
243 if (shared_memory1->mapped_size() < strlen(known_string) ||
244 shared_memory2->mapped_size() < strlen(known_string)) {
245 LOG(ERROR) << "Shared memory size is too small";
246 return false;
247 }
248 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
249
250 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
251 strlen(known_string)) != 0) {
252 LOG(ERROR) << "Incorrect contents in shared_memory2";
253 return false;
254 }
255
256 return true;
257}
258
259// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
260// whether the contents of the attached shared memory region matches |contents|.
261// Consumes a reference to the underlying Mach port.
262bool CheckContentsOfMessage1(const IPC::Message& message,
263 const std::string& contents) {
264 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
265 return CheckContentsOfSharedMemoryHandle(shm, contents);
266}
267
268// Once the test is finished, send a control message to the parent process with
269// the result. The message may require the runloop to be run before its
270// dispatched.
271void SendControlMessage(IPC::Sender* sender, bool success) {
272 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
273 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
274 message->WriteInt(result);
275 sender->Send(message);
276}
277
278// Records the most recently received brokerable attachment's id.
279class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
280 public:
281 void ReceivedBrokerableAttachmentWithId(
282 const IPC::BrokerableAttachment::AttachmentId& id) override {
283 id_ = id;
284 }
285 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
286
287 private:
288 IPC::BrokerableAttachment::AttachmentId id_;
289};
290
291// A broker which always sets the current process as the destination process
292// for attachments.
293class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
294 public:
295 MockBroker() {}
296 ~MockBroker() override {}
erikchena03dde6f2015-10-29 22:37:04297 bool SendAttachmentToProcess(
298 const scoped_refptr<IPC::BrokerableAttachment>& attachment,
299 base::ProcessId destination_process) override {
erikchenb82097cc2015-10-12 23:27:55300 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
301 attachment, base::Process::Current().Pid());
302 }
303};
304
305// Forwards all messages to |listener_|. Quits the message loop after a
306// message is received, or the channel has an error.
307class ProxyListener : public IPC::Listener {
308 public:
309 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
310 ~ProxyListener() override {}
311
312 // The reason for exiting the message loop.
313 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
314
315 bool OnMessageReceived(const IPC::Message& message) override {
316 bool result = false;
317 if (listener_)
318 result = listener_->OnMessageReceived(message);
319 reason_ = MESSAGE_RECEIVED;
320 messages_.push_back(message);
321 base::MessageLoop::current()->QuitNow();
322 return result;
323 }
324
325 void OnChannelError() override {
326 reason_ = CHANNEL_ERROR;
327 base::MessageLoop::current()->QuitNow();
328 }
329
330 void set_listener(IPC::Listener* listener) { listener_ = listener; }
331 Reason get_reason() { return reason_; }
332 IPC::Message get_first_message() {
333 DCHECK(!messages_.empty());
334 return messages_[0];
335 }
336 void pop_first_message() {
337 DCHECK(!messages_.empty());
338 messages_.erase(messages_.begin());
339 }
340 bool has_message() { return !messages_.empty(); }
341
342 private:
343 IPC::Listener* listener_;
344 Reason reason_;
345 std::vector<IPC::Message> messages_;
346};
347
348// Waits for a result to be sent over the channel. Quits the message loop
349// after a message is received, or the channel has an error.
350class ResultListener : public IPC::Listener {
351 public:
352 ResultListener() : result_(RESULT_UNKNOWN) {}
353 ~ResultListener() override {}
354
355 bool OnMessageReceived(const IPC::Message& message) override {
356 base::PickleIterator iter(message);
357
358 int result;
359 EXPECT_TRUE(iter.ReadInt(&result));
360 result_ = static_cast<TestResult>(result);
361 return true;
362 }
363
364 TestResult get_result() { return result_; }
365
366 private:
367 TestResult result_;
368};
369
370class MockPortProvider : public base::PortProvider {
371 public:
372 mach_port_t TaskForPid(base::ProcessHandle process) const override {
373 auto it = port_map_.find(process);
374 if (it != port_map_.end())
375 return it->second;
376 return MACH_PORT_NULL;
377 }
378
379 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
380 port_map_[process] = task_port;
erikchen7c556432015-11-11 22:07:27381 NotifyObservers(process);
erikchenb82097cc2015-10-12 23:27:55382 }
383
erikchen7c556432015-11-11 22:07:27384 void ClearPortMap() { port_map_.clear(); }
385
erikchenb82097cc2015-10-12 23:27:55386 private:
387 std::map<base::ProcessHandle, mach_port_t> port_map_;
388};
389
390// End-to-end tests for the attachment brokering process on Mac.
391// The parent process acts as an unprivileged process. The child process acts
392// as the privileged process.
393class IPCAttachmentBrokerMacTest : public IPCTestBase {
394 public:
395 IPCAttachmentBrokerMacTest() {}
396 ~IPCAttachmentBrokerMacTest() override {}
397
398 base::CommandLine MakeCmdLine(const std::string& procname) override {
399 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
400 // Pass the service name to the child process.
401 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
402 return command_line;
403 }
404
405 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
406 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
407 broker_.reset(broker);
408 }
409
erikchen24e44d32015-10-21 22:28:54410 // Mach Setup that needs to occur before child processes are forked.
411 void MachPreForkSetUp() {
412 service_name_ = IPC::CreateRandomServiceName();
413 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
414 }
415
416 // Mach Setup that needs to occur after child processes are forked.
417 void MachPostForkSetUp() {
418 client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
419 IPC::SendMachPort(
420 client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
421 }
422
erikchenb82097cc2015-10-12 23:27:55423 // Setup shared between tests.
424 void CommonSetUp(const char* name) {
425 Init(name);
erikchen24e44d32015-10-21 22:28:54426 MachPreForkSetUp();
erikchenb82097cc2015-10-12 23:27:55427
428 if (!broker_.get())
429 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
430
erikchen94c9b702015-11-06 21:12:36431 broker_->AddObserver(&observer_, task_runner());
erikchenb82097cc2015-10-12 23:27:55432 CreateChannel(&proxy_listener_);
erikchen86662872016-02-17 04:09:14433 broker_->RegisterBrokerCommunicationChannel(channel());
erikchenb82097cc2015-10-12 23:27:55434 ASSERT_TRUE(ConnectChannel());
435 ASSERT_TRUE(StartClient());
436
erikchen24e44d32015-10-21 22:28:54437 MachPostForkSetUp();
erikchenb82097cc2015-10-12 23:27:55438 active_names_at_start_ = IPC::GetActiveNameCount();
439 get_proxy_listener()->set_listener(&result_listener_);
440 }
441
442 void CheckChildResult() {
443 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
444 get_proxy_listener()->get_reason());
445 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
446 }
447
448 void FinalCleanUp() {
449 // There should be no leaked names.
erikchene50acd882015-11-24 18:28:48450 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
451 base::TimeDelta::FromSeconds(10),
452 active_names_at_start_ == IPC::GetActiveNameCount());
erikchenb82097cc2015-10-12 23:27:55453 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
454
455 // Close the channel so the client's OnChannelError() gets fired.
456 channel()->Close();
457
458 EXPECT_TRUE(WaitForClientShutdown());
459 DestroyChannel();
460 broker_.reset();
461 }
462
463 // Teardown shared between most tests.
464 void CommonTearDown() {
465 CheckChildResult();
466 FinalCleanUp();
467 }
468
469 // Makes a SharedMemory region, fills it with |contents|, sends the handle
470 // over Chrome IPC, and unmaps the region.
471 void SendMessage1(const std::string& contents) {
472 scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
473 IPC::Message* message =
474 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
475 sender()->Send(message);
476 }
477
478 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
479 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
480 AttachmentBrokerObserver* get_observer() { return &observer_; }
481 ResultListener* get_result_listener() { return &result_listener_; }
482
erikchen24e44d32015-10-21 22:28:54483 protected:
484 // The number of active names immediately after set up.
485 mach_msg_type_number_t active_names_at_start_;
486
erikchenb82097cc2015-10-12 23:27:55487 private:
488 ProxyListener proxy_listener_;
489 scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
490 AttachmentBrokerObserver observer_;
491
492 // A port on which the main process listens for mach messages from the child
493 // process.
494 base::mac::ScopedMachReceiveRight server_port_;
495
496 // A port on which the child process listens for mach messages from the main
497 // process.
498 base::mac::ScopedMachSendRight client_port_;
499
erikchenb82097cc2015-10-12 23:27:55500 std::string service_name_;
501
502 ResultListener result_listener_;
503};
504
erikchenb82097cc2015-10-12 23:27:55505// These objects are globally accessible, and are expected to outlive all IPC
506// Channels.
507struct ChildProcessGlobals {
erikchenb82097cc2015-10-12 23:27:55508 MockPortProvider port_provider;
erikchen7c556432015-11-11 22:07:27509
510 // The broker must be destroyed before the port_provider, so that the broker
511 // gets a chance to unregister itself as an observer. This doesn't matter
512 // outside of tests, since neither port_provider nor broker will ever be
513 // destroyed.
514 scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
erikchenb82097cc2015-10-12 23:27:55515 base::mac::ScopedMachSendRight server_task_port;
erikchene50acd882015-11-24 18:28:48516
517 // Total resident memory before running the message loop.
518 mach_vm_size_t initial_resident_size;
519
520 // Whether to emit log statements while processing messages.
521 bool message_logging;
erikchenb82097cc2015-10-12 23:27:55522};
523
erikchen7c556432015-11-11 22:07:27524using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
525 const IPC::Message& message,
526 ChildProcessGlobals* globals);
527
erikchenb82097cc2015-10-12 23:27:55528// Sets up the Mach communication ports with the server. Returns a set of
529// globals that must live at least as long as the test.
530scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
531 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
532 std::string service_name =
533 cmd_line.GetSwitchValueASCII(g_service_switch_name);
534 base::mac::ScopedMachSendRight server_port(
535 IPC::LookupServer(service_name.c_str()));
536 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
537
538 // Send the port that this process is listening on to the server.
markda902e182015-10-20 18:36:13539 IPC::SendMachPort(
540 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
erikchenb82097cc2015-10-12 23:27:55541
542 // Receive the task port of the server process.
543 base::mac::ScopedMachSendRight server_task_port(
markda902e182015-10-20 18:36:13544 IPC::ReceiveMachPort(client_port.get()));
erikchenb82097cc2015-10-12 23:27:55545
546 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
erikchend8a3d9022015-10-22 20:02:02547 globals->broker.reset(
548 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
markda902e182015-10-20 18:36:13549 globals->port_provider.InsertEntry(getppid(), server_task_port.get());
erikchenb82097cc2015-10-12 23:27:55550 globals->server_task_port.reset(server_task_port.release());
erikchene50acd882015-11-24 18:28:48551 globals->message_logging = true;
erikchenb82097cc2015-10-12 23:27:55552 return globals;
553}
554
555int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
556 const char* channel_name) {
557 LOG(INFO) << "Privileged process start.";
558 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
559
560 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
561
562 base::MessageLoopForIO main_message_loop;
563 ProxyListener listener;
564
565 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
566 IPCTestBase::GetChannelName(channel_name), &listener));
erikchena91d05132016-03-21 23:19:40567 globals->broker->RegisterCommunicationChannel(channel.get(), nullptr);
erikchenb82097cc2015-10-12 23:27:55568 CHECK(channel->Connect());
569
erikchene50acd882015-11-24 18:28:48570 globals->initial_resident_size = GetResidentSize();
571
erikchenb82097cc2015-10-12 23:27:55572 while (true) {
erikchene50acd882015-11-24 18:28:48573 if (globals->message_logging)
574 LOG(INFO) << "Privileged process spinning run loop.";
erikchenb82097cc2015-10-12 23:27:55575 base::MessageLoop::current()->Run();
576 ProxyListener::Reason reason = listener.get_reason();
577 if (reason == ProxyListener::CHANNEL_ERROR)
578 break;
579
580 while (listener.has_message()) {
erikchene50acd882015-11-24 18:28:48581 if (globals->message_logging)
582 LOG(INFO) << "Privileged process running callback.";
erikchen7c556432015-11-11 22:07:27583 callback(channel.get(), listener.get_first_message(), globals.get());
erikchene50acd882015-11-24 18:28:48584 if (globals->message_logging)
585 LOG(INFO) << "Privileged process finishing callback.";
erikchenb82097cc2015-10-12 23:27:55586 listener.pop_first_message();
587 }
588 }
589
590 if (active_names_at_start != IPC::GetActiveNameCount()) {
591 LOG(INFO) << "Memory leak!.";
592 }
593 LOG(INFO) << "Privileged process end.";
594 return 0;
595}
596
597// An unprivileged process makes a shared memory region, and writes a string to
598// it. The SharedMemoryHandle is sent to the privileged process using Chrome
599// IPC. The privileged process checks that it received the same memory region.
600TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
erikchenb82097cc2015-10-12 23:27:55601 CommonSetUp("SendSharedMemoryHandle");
602
603 SendMessage1(kDataBuffer1);
604 base::MessageLoop::current()->Run();
605 CommonTearDown();
606}
607
608void SendSharedMemoryHandleCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27609 const IPC::Message& message,
610 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55611 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
612 SendControlMessage(sender, success);
613}
614
615MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
616 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
617 "SendSharedMemoryHandle");
618}
619
620// Similar to SendSharedMemoryHandle, but sends a very long shared memory
621// region.
622TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
erikchenb82097cc2015-10-12 23:27:55623 CommonSetUp("SendSharedMemoryHandleLong");
624
625 std::string buffer(1 << 23, 'a');
626 SendMessage1(buffer);
627 base::MessageLoop::current()->Run();
628 CommonTearDown();
629}
630
631void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27632 const IPC::Message& message,
633 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55634 std::string buffer(1 << 23, 'a');
635 bool success = CheckContentsOfMessage1(message, buffer);
636 SendControlMessage(sender, success);
637}
638
639MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
640 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
641 "SendSharedMemoryHandleLong");
642}
643
644// Similar to SendSharedMemoryHandle, but sends two different shared memory
645// regions in two messages.
646TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
erikchenb82097cc2015-10-12 23:27:55647 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
648
649 SendMessage1(kDataBuffer1);
650 SendMessage1(kDataBuffer2);
651 base::MessageLoop::current()->Run();
652 CommonTearDown();
653}
654
655void SendTwoMessagesDifferentSharedMemoryHandleCallback(
656 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27657 const IPC::Message& message,
658 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55659 static int count = 0;
660 static bool success = true;
661 ++count;
662 if (count == 1) {
663 success &= CheckContentsOfMessage1(message, kDataBuffer1);
664 } else if (count == 2) {
665 success &= CheckContentsOfMessage1(message, kDataBuffer2);
666 SendControlMessage(sender, success);
667 }
668}
669
670MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
671 return CommonPrivilegedProcessMain(
672 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
673 "SendTwoMessagesDifferentSharedMemoryHandle");
674}
675
676// Similar to SendSharedMemoryHandle, but sends the same shared memory region in
677// two messages.
678TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
erikchenb82097cc2015-10-12 23:27:55679 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
680
681 {
682 scoped_ptr<base::SharedMemory> shared_memory(
683 MakeSharedMemory(kDataBuffer1));
684
685 for (int i = 0; i < 2; ++i) {
686 IPC::Message* message =
687 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
688 sender()->Send(message);
689 }
690 }
691
692 base::MessageLoop::current()->Run();
693 CommonTearDown();
694}
695
696void SendTwoMessagesSameSharedMemoryHandleCallback(
697 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27698 const IPC::Message& message,
699 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55700 static int count = 0;
701 static base::SharedMemoryHandle handle1;
702 ++count;
703
704 if (count == 1) {
705 handle1 = GetSharedMemoryHandleFromMsg1(message);
706 } else if (count == 2) {
707 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
708
709 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
710 handle1, handle2, kDataBuffer1);
711 SendControlMessage(sender, success);
712 }
713}
714
715MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
716 return CommonPrivilegedProcessMain(
717 &SendTwoMessagesSameSharedMemoryHandleCallback,
718 "SendTwoMessagesSameSharedMemoryHandle");
719}
720
721// Similar to SendSharedMemoryHandle, but sends one message with two different
722// memory regions.
723TEST_F(IPCAttachmentBrokerMacTest,
724 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
erikchenb82097cc2015-10-12 23:27:55725 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
726
727 {
728 scoped_ptr<base::SharedMemory> shared_memory1(
729 MakeSharedMemory(kDataBuffer1));
730 scoped_ptr<base::SharedMemory> shared_memory2(
731 MakeSharedMemory(kDataBuffer2));
732 IPC::Message* message = new TestSharedMemoryHandleMsg2(
733 shared_memory1->handle(), shared_memory2->handle());
734 sender()->Send(message);
735 }
736 base::MessageLoop::current()->Run();
737 CommonTearDown();
738}
739
740void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
741 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27742 const IPC::Message& message,
743 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55744 base::SharedMemoryHandle handle1;
745 base::SharedMemoryHandle handle2;
746 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
747 LOG(ERROR) << "Failed to deserialize message.";
748 SendControlMessage(sender, false);
749 return;
750 }
751
752 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
753 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
754 SendControlMessage(sender, success);
755}
756
757MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
758 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
759 return CommonPrivilegedProcessMain(
760 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
761 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
762}
763
764// Similar to SendSharedMemoryHandle, but sends one message that contains the
765// same memory region twice.
766TEST_F(IPCAttachmentBrokerMacTest,
767 SendOneMessageWithTwoSameSharedMemoryHandles) {
erikchenb82097cc2015-10-12 23:27:55768 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
769
770 {
771 scoped_ptr<base::SharedMemory> shared_memory(
772 MakeSharedMemory(kDataBuffer1));
773 IPC::Message* message = new TestSharedMemoryHandleMsg2(
774 shared_memory->handle(), shared_memory->handle());
775 sender()->Send(message);
776 }
777 base::MessageLoop::current()->Run();
778 CommonTearDown();
779}
780
781void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
782 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27783 const IPC::Message& message,
784 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55785 base::SharedMemoryHandle handle1;
786 base::SharedMemoryHandle handle2;
787 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
788 LOG(ERROR) << "Failed to deserialize message.";
789 SendControlMessage(sender, false);
790 return;
791 }
792
793 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
794 handle1, handle2, kDataBuffer1);
795 SendControlMessage(sender, success);
796}
797
798MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
799 SendOneMessageWithTwoSameSharedMemoryHandles) {
800 return CommonPrivilegedProcessMain(
801 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
802 "SendOneMessageWithTwoSameSharedMemoryHandles");
803}
804
805// Sends one message with two Posix FDs and two Mach ports.
806TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
erikchenb82097cc2015-10-12 23:27:55807 base::ScopedTempDir temp_dir;
808 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
809 base::FilePath fp1, fp2;
810 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
811 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
812
813 CommonSetUp("SendPosixFDAndMachPort");
814
815 {
816 scoped_ptr<base::SharedMemory> shared_memory1(
817 MakeSharedMemory(kDataBuffer1));
818 scoped_ptr<base::SharedMemory> shared_memory2(
819 MakeSharedMemory(kDataBuffer2));
820
821 base::FileDescriptor file_descriptor1(
822 MakeFileDescriptor(fp1, kDataBuffer3));
823 base::FileDescriptor file_descriptor2(
824 MakeFileDescriptor(fp2, kDataBuffer4));
825
826 IPC::Message* message = new TestSharedMemoryHandleMsg3(
827 file_descriptor1, shared_memory1->handle(), file_descriptor2,
828 shared_memory2->handle());
829 sender()->Send(message);
830 }
831
832 base::MessageLoop::current()->Run();
833 CommonTearDown();
834}
835
836void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27837 const IPC::Message& message,
838 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55839 TestSharedMemoryHandleMsg3::Schema::Param p;
840 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
841 LOG(ERROR) << "Failed to deserialize message.";
842 SendControlMessage(sender, false);
843 return;
844 }
845
tzik55e3e4d2016-03-08 05:47:44846 base::SharedMemoryHandle handle1 = std::get<1>(p);
847 base::SharedMemoryHandle handle2 = std::get<3>(p);
erikchenb82097cc2015-10-12 23:27:55848 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
849 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
850 if (!success1)
851 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
852
853 bool success2 =
tzik55e3e4d2016-03-08 05:47:44854 CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) &&
855 CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4);
erikchenb82097cc2015-10-12 23:27:55856 if (!success2)
857 LOG(ERROR) << "FileDescriptors have wrong contents.";
858
859 SendControlMessage(sender, success1 && success2);
860}
861
862MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
863 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
864 "SendPosixFDAndMachPort");
865}
866
867// Similar to SendHandle, except the attachment's destination process is this
868// process. This is an unrealistic scenario, but simulates an unprivileged
869// process sending an attachment to another unprivileged process.
870TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
erikchenb82097cc2015-10-12 23:27:55871 SetBroker(new MockBroker);
872 CommonSetUp("SendSharedMemoryHandleToSelf");
873
874 // Technically, the channel is an endpoint, but we need the proxy listener to
875 // receive the messages so that it can quit the message loop.
876 channel()->SetAttachmentBrokerEndpoint(false);
877 get_proxy_listener()->set_listener(get_broker());
878
879 {
880 scoped_ptr<base::SharedMemory> shared_memory(
881 MakeSharedMemory(kDataBuffer1));
882 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
883 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
884
885 IPC::Message* message =
886 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
887 sender()->Send(message);
erikchen94c9b702015-11-06 21:12:36888
889 // Wait until the child process has sent this process a message.
erikchenb82097cc2015-10-12 23:27:55890 base::MessageLoop::current()->Run();
891
erikchen94c9b702015-11-06 21:12:36892 // Wait for any asynchronous activity to complete.
893 base::MessageLoop::current()->RunUntilIdle();
894
erikchenb82097cc2015-10-12 23:27:55895 // Get the received attachment.
896 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
erikchen94c9b702015-11-06 21:12:36897 ASSERT_TRUE(id);
erikchenb82097cc2015-10-12 23:27:55898 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
899 get_broker()->GetAttachmentWithId(*id, &received_attachment);
900 ASSERT_NE(received_attachment.get(), nullptr);
901
902 // Check that it's has the same name, but that the ref count has increased.
903 base::mac::ScopedMachSendRight memory_object(
904 GetMachPortFromBrokeredAttachment(received_attachment));
905 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
906 EXPECT_EQ(ref_count + 1,
907 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
908 MACH_PORT_RIGHT_SEND));
909 }
910
911 FinalCleanUp();
912}
913
914void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27915 const IPC::Message&,
916 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55917 // Do nothing special. The default behavior already runs the
918 // AttachmentBrokerPrivilegedMac.
919}
920
921MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
922 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
923 "SendSharedMemoryHandleToSelf");
924}
925
erikchen24e44d32015-10-21 22:28:54926// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
927// Channel.
928TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
erikchen24e44d32015-10-21 22:28:54929 Init("SendSharedMemoryHandleChannelProxy");
930 MachPreForkSetUp();
931
932 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
erikchen94c9b702015-11-06 21:12:36933 get_broker()->AddObserver(get_observer(), task_runner());
erikchen24e44d32015-10-21 22:28:54934
935 scoped_ptr<base::Thread> thread(
936 new base::Thread("ChannelProxyTestServerThread"));
937 base::Thread::Options options;
938 options.message_loop_type = base::MessageLoop::TYPE_IO;
939 thread->StartWithOptions(options);
940
941 CreateChannelProxy(get_proxy_listener(), thread->task_runner().get());
erikchen86662872016-02-17 04:09:14942 get_broker()->RegisterBrokerCommunicationChannel(channel_proxy());
erikchen24e44d32015-10-21 22:28:54943
944 ASSERT_TRUE(StartClient());
945
946 MachPostForkSetUp();
947 active_names_at_start_ = IPC::GetActiveNameCount();
948 get_proxy_listener()->set_listener(get_result_listener());
949
950 SendMessage1(kDataBuffer1);
951 base::MessageLoop::current()->Run();
952
953 CheckChildResult();
954
955 // There should be no leaked names.
956 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
957
958 // Close the channel so the client's OnChannelError() gets fired.
959 channel_proxy()->Close();
960
961 EXPECT_TRUE(WaitForClientShutdown());
962 DestroyChannelProxy();
963}
964
965void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27966 const IPC::Message& message,
967 ChildProcessGlobals* globals) {
erikchen24e44d32015-10-21 22:28:54968 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
969 SendControlMessage(sender, success);
970}
971
972MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
973 return CommonPrivilegedProcessMain(
974 &SendSharedMemoryHandleChannelProxyCallback,
975 "SendSharedMemoryHandleChannelProxy");
976}
977
erikchen328bf3f2015-10-24 00:46:54978// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
979// ShareToProcess().
980TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
erikchen328bf3f2015-10-24 00:46:54981 CommonSetUp("ShareToProcess");
982
983 {
984 scoped_ptr<base::SharedMemory> shared_memory(
985 MakeSharedMemory(kDataBuffer1));
986 base::SharedMemoryHandle new_handle;
987 ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
988 IPC::Message* message =
989 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
990 sender()->Send(message);
991 }
992
993 base::MessageLoop::current()->Run();
994 CommonTearDown();
995}
996
erikchen7c556432015-11-11 22:07:27997void ShareToProcessCallback(IPC::Sender* sender,
998 const IPC::Message& message,
999 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541000 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
1001 SendControlMessage(sender, success);
1002}
1003
1004MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
1005 return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
1006}
1007
1008// Similar to ShareToProcess, but instead shares the memory object only with
1009// read permissions.
1010TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
erikchen328bf3f2015-10-24 00:46:541011 CommonSetUp("ShareReadOnlyToProcess");
1012
1013 {
1014 scoped_ptr<base::SharedMemory> shared_memory(
1015 MakeSharedMemory(kDataBuffer1));
1016 base::SharedMemoryHandle new_handle;
1017 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
1018 IPC::Message* message =
1019 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1020 sender()->Send(message);
1021 }
1022
1023 base::MessageLoop::current()->Run();
1024 CommonTearDown();
1025}
1026
1027void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:271028 const IPC::Message& message,
1029 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541030 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1031
1032 // Try to map the memory as writable.
1033 scoped_ptr<base::SharedMemory> shared_memory(
1034 MapSharedMemoryHandle(shm, false));
1035 ASSERT_EQ(nullptr, shared_memory->memory());
1036
1037 // Now try as read-only.
1038 scoped_ptr<base::SharedMemory> shared_memory2(
1039 MapSharedMemoryHandle(shm.Duplicate(), true));
1040 int current_prot, max_prot;
1041 ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
1042 shared_memory2->mapped_size(),
1043 &current_prot, &max_prot));
1044 ASSERT_EQ(VM_PROT_READ, current_prot);
1045 ASSERT_EQ(VM_PROT_READ, max_prot);
1046
1047 bool success =
1048 memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
1049 SendControlMessage(sender, success);
1050}
1051
1052MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
1053 return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
1054 "ShareReadOnlyToProcess");
1055}
1056
erikchen7c556432015-11-11 22:07:271057// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
1058// not have the task port for the parent process.
1059TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
erikchen7c556432015-11-11 22:07:271060 SetBroker(new MockBroker);
1061 CommonSetUp("SendSharedMemoryHandleToSelfDelayedPort");
1062
1063 // Technically, the channel is an endpoint, but we need the proxy listener to
1064 // receive the messages so that it can quit the message loop.
1065 channel()->SetAttachmentBrokerEndpoint(false);
1066 get_proxy_listener()->set_listener(get_broker());
1067
1068 {
1069 scoped_ptr<base::SharedMemory> shared_memory(
1070 MakeSharedMemory(kDataBuffer1));
1071 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
1072 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
1073
1074 std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
1075 const int kMessagesToTest = 3;
1076 for (int i = 0; i < kMessagesToTest; ++i) {
1077 base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
1078 ids.push_back(
1079 IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
1080 IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
1081 h.GetMemoryObject(), getpid(), ids[i]);
1082 sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
1083
1084 // Send a dummy message, which will trigger the callback handler in the
1085 // child process.
1086 sender()->Send(new TestSharedMemoryHandleMsg4(1));
1087 }
1088
1089 int received_message_count = 0;
1090 while (received_message_count < kMessagesToTest) {
1091 // Wait until the child process has sent this process a message.
1092 base::MessageLoop::current()->Run();
1093
1094 // Wait for any asynchronous activity to complete.
1095 base::MessageLoop::current()->RunUntilIdle();
1096
1097 while (get_proxy_listener()->has_message()) {
1098 get_proxy_listener()->pop_first_message();
1099 received_message_count++;
1100 }
1101 }
1102
1103 for (int i = 0; i < kMessagesToTest; ++i) {
1104 IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
1105 ASSERT_TRUE(id);
1106 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
1107 get_broker()->GetAttachmentWithId(*id, &received_attachment);
1108 ASSERT_NE(received_attachment.get(), nullptr);
1109
1110 base::mac::ScopedMachSendRight memory_object(
1111 GetMachPortFromBrokeredAttachment(received_attachment));
1112 ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
1113 }
1114
1115 // Check that the ref count hasn't changed.
1116 EXPECT_EQ(ref_count,
1117 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
1118 MACH_PORT_RIGHT_SEND));
1119 }
1120
1121 FinalCleanUp();
1122}
1123
1124void SendSharedMemoryHandleToSelfDelayedPortCallback(
1125 IPC::Sender* sender,
1126 const IPC::Message& message,
1127 ChildProcessGlobals* globals) {
1128 static int i = 0;
1129 static base::ProcessId pid = message.get_sender_pid();
1130 static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
1131 ++i;
1132
1133 if (i == 1) {
1134 // Pretend to not have the task port for the parent.
1135 globals->port_provider.ClearPortMap();
1136 } else if (i == 2) {
1137 // Intentionally do nothing.
1138 } else if (i == 3) {
1139 // Setting the task port should trigger callbacks, eventually resulting in
1140 // multiple attachment broker messages.
1141 globals->port_provider.InsertEntry(pid, task_port);
1142 }
1143}
1144
1145MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
1146 return CommonPrivilegedProcessMain(
1147 &SendSharedMemoryHandleToSelfDelayedPortCallback,
1148 "SendSharedMemoryHandleToSelfDelayedPort");
1149}
1150
erikchene50acd882015-11-24 18:28:481151// Tests the memory usage characteristics of attachment brokering a single large
1152// message. This test has the *potential* to be flaky, since it compares
1153// resident memory at different points in time, and that measurement is
1154// non-deterministic.
1155TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) {
erikchene50acd882015-11-24 18:28:481156 CommonSetUp("MemoryUsageLargeMessage");
1157
1158 std::string test_string(g_large_message_size, 'a');
1159 SendMessage1(test_string);
1160 base::MessageLoop::current()->Run();
1161 CommonTearDown();
1162}
1163
1164void MemoryUsageLargeMessageCallback(IPC::Sender* sender,
1165 const IPC::Message& message,
1166 ChildProcessGlobals* globals) {
1167 EXPECT_LE(GetResidentSize(),
1168 globals->initial_resident_size + g_expected_memory_increase);
1169
1170 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1171 scoped_ptr<base::SharedMemory> shared_memory(
1172 MapSharedMemoryHandle(shm, false));
1173 EXPECT_LE(GetResidentSize(),
1174 globals->initial_resident_size + g_expected_memory_increase);
1175
1176 char* addr = static_cast<char*>(shared_memory->memory());
1177 for (size_t i = 0; i < g_large_message_size; i += 1024) {
1178 addr[i] = 'a';
1179 }
1180 EXPECT_GE(GetResidentSize(),
1181 globals->initial_resident_size + g_large_message_size);
1182
1183 shared_memory.reset();
1184#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
1185 !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
1186 !defined(UNDEFINED_SANITIZER)
1187 // Under a sanitizer build, releasing memory does not necessarily reduce the
1188 // amount of resident memory.
1189 EXPECT_LE(GetResidentSize(),
1190 globals->initial_resident_size + g_expected_memory_increase);
1191#endif
1192
1193 SendControlMessage(sender, true);
1194}
1195
1196MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) {
1197 return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback,
1198 "MemoryUsageLargeMessage");
1199}
1200
1201// Tests the memory usage characteristics of attachment brokering many small
1202// messages. This test has the *potential* to be flaky, since it compares
1203// resident memory at different points in time, and that measurement is
1204// non-deterministic.
1205TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) {
erikchene50acd882015-11-24 18:28:481206 CommonSetUp("MemoryUsageManyMessages");
1207
1208 for (int i = 0; i < g_large_message_count; ++i) {
1209 std::string message = base::IntToString(i);
1210 message += '\0';
1211 size_t end = message.size();
1212 message.resize(g_medium_message_size);
1213 std::fill(message.begin() + end, message.end(), 'a');
1214 SendMessage1(message);
1215
1216 base::MessageLoop::current()->RunUntilIdle();
1217 }
1218
1219 if (get_result_listener()->get_result() == RESULT_UNKNOWN)
1220 base::MessageLoop::current()->Run();
1221
1222 CommonTearDown();
1223}
1224
1225void MemoryUsageManyMessagesCallback(IPC::Sender* sender,
1226 const IPC::Message& message,
1227 ChildProcessGlobals* globals) {
1228 static int message_index = 0;
1229
1230 {
1231 // Map the shared memory, and make sure that its pages are counting towards
1232 // resident size.
1233 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1234 scoped_ptr<base::SharedMemory> shared_memory(
1235 MapSharedMemoryHandle(shm, false));
1236
1237 char* addr = static_cast<char*>(shared_memory->memory());
1238 std::string message_string(addr);
1239 int message_int;
1240 ASSERT_TRUE(base::StringToInt(message_string, &message_int));
1241 ASSERT_EQ(message_index, message_int);
1242 for (size_t i = 0; i < g_medium_message_size; i += 1024) {
1243 addr[i] = 'a';
1244 }
1245 }
1246
1247 ++message_index;
1248
1249 if (message_index == 1) {
1250 // Disable message logging, since it significantly contributes towards total
1251 // memory usage.
1252 LOG(INFO) << "Disable privileged process message logging.";
1253 globals->message_logging = false;
1254 }
1255
1256 if (message_index == g_large_message_count) {
1257 size_t memory_increase_kb =
1258 (GetResidentSize() - globals->initial_resident_size) / 1024;
1259 LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb;
1260
1261#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
1262 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
1263 defined(UNDEFINED_SANITIZER)
1264 // Under a sanitizer build, releasing memory does not necessarily reduce the
1265 // amount of resident memory.
1266 bool success = true;
1267#else
1268 // The total increase in resident size should be less than 1MB. The exact
1269 // amount is not deterministic.
1270 bool success = memory_increase_kb < 1024;
1271#endif
1272
1273 SendControlMessage(sender, success);
1274 }
1275}
1276
1277MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) {
1278 return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback,
1279 "MemoryUsageManyMessages");
1280}
1281
erikchenb82097cc2015-10-12 23:27:551282} // namespace