blob: be4f3c515021b5cb5e2c2cb07979eb2c4691e279 [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
12#include "base/command_line.h"
13#include "base/files/file_util.h"
14#include "base/files/scoped_file.h"
15#include "base/files/scoped_temp_dir.h"
erikchen328bf3f2015-10-24 00:46:5416#include "base/mac/mac_util.h"
erikchene50acd882015-11-24 18:28:4817#include "base/mac/mach_logging.h"
erikchenb82097cc2015-10-12 23:27:5518#include "base/memory/scoped_ptr.h"
19#include "base/memory/shared_memory.h"
erikchene50acd882015-11-24 18:28:4820#include "base/strings/string_number_conversions.h"
21#include "base/synchronization/spin_wait.h"
22#include "base/time/time.h"
erikchen7c556432015-11-11 22:07:2723#include "ipc/attachment_broker_messages.h"
erikchenb82097cc2015-10-12 23:27:5524#include "ipc/attachment_broker_privileged_mac.h"
25#include "ipc/attachment_broker_unprivileged_mac.h"
26#include "ipc/ipc_listener.h"
27#include "ipc/ipc_message.h"
28#include "ipc/ipc_test_base.h"
29#include "ipc/ipc_test_messages.h"
30#include "ipc/test_util_mac.h"
31
32namespace {
33
34const char kDataBuffer1[] = "This is some test data to write to the file.";
35const char kDataBuffer2[] = "The lazy dog and a fox.";
36const char kDataBuffer3[] = "Two green bears but not a potato.";
37const char kDataBuffer4[] = "Red potato is best potato.";
38const std::string g_service_switch_name = "service_name";
erikchene50acd882015-11-24 18:28:4839const size_t g_large_message_size = 8 * 1024 * 1024;
40const int g_large_message_count = 1000;
41const size_t g_medium_message_size = 512 * 1024;
42
43// Running the message loop is expected to increase the number of resident
44// pages. The exact amount is non-deterministic, but for a simple test suite
45// like this one, the increase is expected to be less than 1 MB.
46const size_t g_expected_memory_increase = 1024 * 1024;
erikchenb82097cc2015-10-12 23:27:5547
48enum TestResult {
49 RESULT_UNKNOWN,
50 RESULT_SUCCESS,
51 RESULT_FAILURE,
52};
53
erikchene50acd882015-11-24 18:28:4854mach_vm_size_t GetResidentSize() {
55 task_basic_info_64 info;
56 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
57 kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
58 reinterpret_cast<task_info_t>(&info), &count);
59 MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size.";
60
61 return info.resident_size;
62}
63
erikchenb82097cc2015-10-12 23:27:5564base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
65 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
66 if (attachment->GetType() !=
67 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
68 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
69 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
70 }
71
72 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
73 LOG(INFO) << "Brokerable type not MACH_PORT.";
74 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
75 }
76
77 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
78 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
79 return base::mac::ScopedMachSendRight(
80 received_mach_port_attachment->get_mach_port());
81}
82
83// Makes a Mach port backed SharedMemory region and fills it with |contents|.
84scoped_ptr<base::SharedMemory> MakeSharedMemory(const std::string& contents) {
85 base::SharedMemoryHandle shm(contents.size());
86 if (!shm.IsValid()) {
87 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
88 return nullptr;
89 }
90 scoped_ptr<base::SharedMemory> shared_memory(
91 new base::SharedMemory(shm, false));
92 shared_memory->Map(contents.size());
93 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
94 return shared_memory;
95}
96
97// |message| must be deserializable as a TestSharedMemoryHandleMsg1.
98base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
99 const IPC::Message& message) {
100 // Expect a message with a brokered attachment.
101 if (!message.HasBrokerableAttachments()) {
102 LOG(ERROR) << "Message missing brokerable attachment.";
103 return base::SharedMemoryHandle();
104 }
105
106 TestSharedMemoryHandleMsg1::Schema::Param p;
107 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
108 LOG(ERROR) << "Failed to deserialize message.";
109 return base::SharedMemoryHandle();
110 }
111
112 return base::get<1>(p);
113}
114
115// |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
116// whether deserialization was successful. |handle1| and |handle2| are output
117// variables populated on success.
118bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
119 base::SharedMemoryHandle* handle1,
120 base::SharedMemoryHandle* handle2) {
121 // Expect a message with a brokered attachment.
122 if (!message.HasBrokerableAttachments()) {
123 LOG(ERROR) << "Message missing brokerable attachment.";
124 return false;
125 }
126
127 TestSharedMemoryHandleMsg2::Schema::Param p;
128 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
129 LOG(ERROR) << "Failed to deserialize message.";
130 return false;
131 }
132
133 *handle1 = base::get<0>(p);
134 *handle2 = base::get<1>(p);
135 return true;
136}
137
138// Returns |nullptr| on error.
139scoped_ptr<base::SharedMemory> MapSharedMemoryHandle(
erikchen328bf3f2015-10-24 00:46:54140 const base::SharedMemoryHandle& shm,
141 bool read_only) {
erikchenb82097cc2015-10-12 23:27:55142 if (!shm.IsValid()) {
143 LOG(ERROR) << "Invalid SharedMemoryHandle";
144 return nullptr;
145 }
146
147 size_t size;
148 if (!shm.GetSize(&size)) {
149 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
150 return nullptr;
151 }
152
153 scoped_ptr<base::SharedMemory> shared_memory(
erikchen328bf3f2015-10-24 00:46:54154 new base::SharedMemory(shm, read_only));
erikchenb82097cc2015-10-12 23:27:55155 shared_memory->Map(size);
156 return shared_memory;
157}
158
159// This method maps the SharedMemoryHandle, checks the contents, and then
160// consumes a reference to the underlying Mach port.
161bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
162 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54163 scoped_ptr<base::SharedMemory> shared_memory(
164 MapSharedMemoryHandle(shm, false));
erikchenb82097cc2015-10-12 23:27:55165
166 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
167 LOG(ERROR) << "Shared Memory contents not equivalent";
168 return false;
169 }
170 return true;
171}
172
173// This method mmaps the FileDescriptor, checks the contents, and then munmaps
174// the FileDescriptor and closes the underlying fd.
175bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
176 const std::string& contents) {
177 base::ScopedFD fd_closer(file_descriptor.fd);
178 lseek(file_descriptor.fd, 0, SEEK_SET);
179 scoped_ptr<char, base::FreeDeleter> buffer(
180 static_cast<char*>(malloc(contents.size())));
181 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
182 return false;
183
184 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
185 return result == 0;
186}
187
188// Open |fp| and populate it with |contents|.
189base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
190 const std::string& contents) {
191 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
192 base::ScopedFD fd_closer(fd);
193 if (fd <= 0) {
194 LOG(ERROR) << "Error opening file at: " << fp.value();
195 return base::FileDescriptor();
196 }
197
198 if (lseek(fd, 0, SEEK_SET) != 0) {
199 LOG(ERROR) << "Error changing offset";
200 return base::FileDescriptor();
201 }
202
203 if (write(fd, contents.c_str(), contents.size()) !=
204 static_cast<ssize_t>(contents.size())) {
205 LOG(ERROR) << "Error writing to file";
206 return base::FileDescriptor();
207 }
208
209 return base::FileDescriptor(fd_closer.release(), true);
210}
211
212// Maps both handles, then checks that their contents matches |contents|. Then
213// checks that changes to one are reflected in the other. Then consumes
214// references to both underlying Mach ports.
215bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
216 const base::SharedMemoryHandle& handle1,
217 const base::SharedMemoryHandle& handle2,
218 const std::string& contents) {
erikchen328bf3f2015-10-24 00:46:54219 scoped_ptr<base::SharedMemory> shared_memory1(
220 MapSharedMemoryHandle(handle1, false));
221 scoped_ptr<base::SharedMemory> shared_memory2(
222 MapSharedMemoryHandle(handle2, false));
erikchenb82097cc2015-10-12 23:27:55223
224 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
225 0) {
226 LOG(ERROR) << "Incorrect contents in shared_memory1";
227 return false;
228 }
229
230 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
231 contents.size()) != 0) {
232 LOG(ERROR) << "Incorrect contents in shared_memory2";
233 return false;
234 }
235
236 // Updating shared_memory1 should update shared_memory2.
237 const char known_string[] = "string bean";
238 if (shared_memory1->mapped_size() < strlen(known_string) ||
239 shared_memory2->mapped_size() < strlen(known_string)) {
240 LOG(ERROR) << "Shared memory size is too small";
241 return false;
242 }
243 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
244
245 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
246 strlen(known_string)) != 0) {
247 LOG(ERROR) << "Incorrect contents in shared_memory2";
248 return false;
249 }
250
251 return true;
252}
253
254// |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
255// whether the contents of the attached shared memory region matches |contents|.
256// Consumes a reference to the underlying Mach port.
257bool CheckContentsOfMessage1(const IPC::Message& message,
258 const std::string& contents) {
259 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
260 return CheckContentsOfSharedMemoryHandle(shm, contents);
261}
262
263// Once the test is finished, send a control message to the parent process with
264// the result. The message may require the runloop to be run before its
265// dispatched.
266void SendControlMessage(IPC::Sender* sender, bool success) {
267 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
268 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
269 message->WriteInt(result);
270 sender->Send(message);
271}
272
273// Records the most recently received brokerable attachment's id.
274class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
275 public:
276 void ReceivedBrokerableAttachmentWithId(
277 const IPC::BrokerableAttachment::AttachmentId& id) override {
278 id_ = id;
279 }
280 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
281
282 private:
283 IPC::BrokerableAttachment::AttachmentId id_;
284};
285
286// A broker which always sets the current process as the destination process
287// for attachments.
288class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
289 public:
290 MockBroker() {}
291 ~MockBroker() override {}
erikchena03dde6f2015-10-29 22:37:04292 bool SendAttachmentToProcess(
293 const scoped_refptr<IPC::BrokerableAttachment>& attachment,
294 base::ProcessId destination_process) override {
erikchenb82097cc2015-10-12 23:27:55295 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
296 attachment, base::Process::Current().Pid());
297 }
298};
299
300// Forwards all messages to |listener_|. Quits the message loop after a
301// message is received, or the channel has an error.
302class ProxyListener : public IPC::Listener {
303 public:
304 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
305 ~ProxyListener() override {}
306
307 // The reason for exiting the message loop.
308 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
309
310 bool OnMessageReceived(const IPC::Message& message) override {
311 bool result = false;
312 if (listener_)
313 result = listener_->OnMessageReceived(message);
314 reason_ = MESSAGE_RECEIVED;
315 messages_.push_back(message);
316 base::MessageLoop::current()->QuitNow();
317 return result;
318 }
319
320 void OnChannelError() override {
321 reason_ = CHANNEL_ERROR;
322 base::MessageLoop::current()->QuitNow();
323 }
324
325 void set_listener(IPC::Listener* listener) { listener_ = listener; }
326 Reason get_reason() { return reason_; }
327 IPC::Message get_first_message() {
328 DCHECK(!messages_.empty());
329 return messages_[0];
330 }
331 void pop_first_message() {
332 DCHECK(!messages_.empty());
333 messages_.erase(messages_.begin());
334 }
335 bool has_message() { return !messages_.empty(); }
336
337 private:
338 IPC::Listener* listener_;
339 Reason reason_;
340 std::vector<IPC::Message> messages_;
341};
342
343// Waits for a result to be sent over the channel. Quits the message loop
344// after a message is received, or the channel has an error.
345class ResultListener : public IPC::Listener {
346 public:
347 ResultListener() : result_(RESULT_UNKNOWN) {}
348 ~ResultListener() override {}
349
350 bool OnMessageReceived(const IPC::Message& message) override {
351 base::PickleIterator iter(message);
352
353 int result;
354 EXPECT_TRUE(iter.ReadInt(&result));
355 result_ = static_cast<TestResult>(result);
356 return true;
357 }
358
359 TestResult get_result() { return result_; }
360
361 private:
362 TestResult result_;
363};
364
365class MockPortProvider : public base::PortProvider {
366 public:
367 mach_port_t TaskForPid(base::ProcessHandle process) const override {
368 auto it = port_map_.find(process);
369 if (it != port_map_.end())
370 return it->second;
371 return MACH_PORT_NULL;
372 }
373
374 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
375 port_map_[process] = task_port;
erikchen7c556432015-11-11 22:07:27376 NotifyObservers(process);
erikchenb82097cc2015-10-12 23:27:55377 }
378
erikchen7c556432015-11-11 22:07:27379 void ClearPortMap() { port_map_.clear(); }
380
erikchenb82097cc2015-10-12 23:27:55381 private:
382 std::map<base::ProcessHandle, mach_port_t> port_map_;
383};
384
385// End-to-end tests for the attachment brokering process on Mac.
386// The parent process acts as an unprivileged process. The child process acts
387// as the privileged process.
388class IPCAttachmentBrokerMacTest : public IPCTestBase {
389 public:
390 IPCAttachmentBrokerMacTest() {}
391 ~IPCAttachmentBrokerMacTest() override {}
392
393 base::CommandLine MakeCmdLine(const std::string& procname) override {
394 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
395 // Pass the service name to the child process.
396 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
397 return command_line;
398 }
399
400 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
401 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
402 broker_.reset(broker);
403 }
404
erikchen24e44d32015-10-21 22:28:54405 // Mach Setup that needs to occur before child processes are forked.
406 void MachPreForkSetUp() {
407 service_name_ = IPC::CreateRandomServiceName();
408 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
409 }
410
411 // Mach Setup that needs to occur after child processes are forked.
412 void MachPostForkSetUp() {
413 client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
414 IPC::SendMachPort(
415 client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
416 }
417
erikchenb82097cc2015-10-12 23:27:55418 // Setup shared between tests.
419 void CommonSetUp(const char* name) {
420 Init(name);
erikchen24e44d32015-10-21 22:28:54421 MachPreForkSetUp();
erikchenb82097cc2015-10-12 23:27:55422
423 if (!broker_.get())
424 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
425
erikchen94c9b702015-11-06 21:12:36426 broker_->AddObserver(&observer_, task_runner());
erikchenb82097cc2015-10-12 23:27:55427 CreateChannel(&proxy_listener_);
428 broker_->DesignateBrokerCommunicationChannel(channel());
429 ASSERT_TRUE(ConnectChannel());
430 ASSERT_TRUE(StartClient());
431
erikchen24e44d32015-10-21 22:28:54432 MachPostForkSetUp();
erikchenb82097cc2015-10-12 23:27:55433 active_names_at_start_ = IPC::GetActiveNameCount();
434 get_proxy_listener()->set_listener(&result_listener_);
435 }
436
437 void CheckChildResult() {
438 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
439 get_proxy_listener()->get_reason());
440 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
441 }
442
443 void FinalCleanUp() {
444 // There should be no leaked names.
erikchene50acd882015-11-24 18:28:48445 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
446 base::TimeDelta::FromSeconds(10),
447 active_names_at_start_ == IPC::GetActiveNameCount());
erikchenb82097cc2015-10-12 23:27:55448 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
449
450 // Close the channel so the client's OnChannelError() gets fired.
451 channel()->Close();
452
453 EXPECT_TRUE(WaitForClientShutdown());
454 DestroyChannel();
455 broker_.reset();
456 }
457
458 // Teardown shared between most tests.
459 void CommonTearDown() {
460 CheckChildResult();
461 FinalCleanUp();
462 }
463
464 // Makes a SharedMemory region, fills it with |contents|, sends the handle
465 // over Chrome IPC, and unmaps the region.
466 void SendMessage1(const std::string& contents) {
467 scoped_ptr<base::SharedMemory> shared_memory(MakeSharedMemory(contents));
468 IPC::Message* message =
469 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
470 sender()->Send(message);
471 }
472
473 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
474 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
475 AttachmentBrokerObserver* get_observer() { return &observer_; }
476 ResultListener* get_result_listener() { return &result_listener_; }
477
erikchen24e44d32015-10-21 22:28:54478 protected:
479 // The number of active names immediately after set up.
480 mach_msg_type_number_t active_names_at_start_;
481
erikchenb82097cc2015-10-12 23:27:55482 private:
483 ProxyListener proxy_listener_;
484 scoped_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
485 AttachmentBrokerObserver observer_;
486
487 // A port on which the main process listens for mach messages from the child
488 // process.
489 base::mac::ScopedMachReceiveRight server_port_;
490
491 // A port on which the child process listens for mach messages from the main
492 // process.
493 base::mac::ScopedMachSendRight client_port_;
494
erikchenb82097cc2015-10-12 23:27:55495 std::string service_name_;
496
497 ResultListener result_listener_;
498};
499
erikchenb82097cc2015-10-12 23:27:55500// These objects are globally accessible, and are expected to outlive all IPC
501// Channels.
502struct ChildProcessGlobals {
erikchenb82097cc2015-10-12 23:27:55503 MockPortProvider port_provider;
erikchen7c556432015-11-11 22:07:27504
505 // The broker must be destroyed before the port_provider, so that the broker
506 // gets a chance to unregister itself as an observer. This doesn't matter
507 // outside of tests, since neither port_provider nor broker will ever be
508 // destroyed.
509 scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
erikchenb82097cc2015-10-12 23:27:55510 base::mac::ScopedMachSendRight server_task_port;
erikchene50acd882015-11-24 18:28:48511
512 // Total resident memory before running the message loop.
513 mach_vm_size_t initial_resident_size;
514
515 // Whether to emit log statements while processing messages.
516 bool message_logging;
erikchenb82097cc2015-10-12 23:27:55517};
518
erikchen7c556432015-11-11 22:07:27519using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
520 const IPC::Message& message,
521 ChildProcessGlobals* globals);
522
erikchenb82097cc2015-10-12 23:27:55523// Sets up the Mach communication ports with the server. Returns a set of
524// globals that must live at least as long as the test.
525scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
526 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
527 std::string service_name =
528 cmd_line.GetSwitchValueASCII(g_service_switch_name);
529 base::mac::ScopedMachSendRight server_port(
530 IPC::LookupServer(service_name.c_str()));
531 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
532
533 // Send the port that this process is listening on to the server.
markda902e182015-10-20 18:36:13534 IPC::SendMachPort(
535 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
erikchenb82097cc2015-10-12 23:27:55536
537 // Receive the task port of the server process.
538 base::mac::ScopedMachSendRight server_task_port(
markda902e182015-10-20 18:36:13539 IPC::ReceiveMachPort(client_port.get()));
erikchenb82097cc2015-10-12 23:27:55540
541 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
erikchend8a3d9022015-10-22 20:02:02542 globals->broker.reset(
543 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
markda902e182015-10-20 18:36:13544 globals->port_provider.InsertEntry(getppid(), server_task_port.get());
erikchenb82097cc2015-10-12 23:27:55545 globals->server_task_port.reset(server_task_port.release());
erikchene50acd882015-11-24 18:28:48546 globals->message_logging = true;
erikchenb82097cc2015-10-12 23:27:55547 return globals;
548}
549
550int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
551 const char* channel_name) {
552 LOG(INFO) << "Privileged process start.";
553 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
554
555 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
556
557 base::MessageLoopForIO main_message_loop;
558 ProxyListener listener;
559
560 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
561 IPCTestBase::GetChannelName(channel_name), &listener));
erikchend8a3d9022015-10-22 20:02:02562 globals->broker->RegisterCommunicationChannel(channel.get());
erikchenb82097cc2015-10-12 23:27:55563 CHECK(channel->Connect());
564
erikchene50acd882015-11-24 18:28:48565 globals->initial_resident_size = GetResidentSize();
566
erikchenb82097cc2015-10-12 23:27:55567 while (true) {
erikchene50acd882015-11-24 18:28:48568 if (globals->message_logging)
569 LOG(INFO) << "Privileged process spinning run loop.";
erikchenb82097cc2015-10-12 23:27:55570 base::MessageLoop::current()->Run();
571 ProxyListener::Reason reason = listener.get_reason();
572 if (reason == ProxyListener::CHANNEL_ERROR)
573 break;
574
575 while (listener.has_message()) {
erikchene50acd882015-11-24 18:28:48576 if (globals->message_logging)
577 LOG(INFO) << "Privileged process running callback.";
erikchen7c556432015-11-11 22:07:27578 callback(channel.get(), listener.get_first_message(), globals.get());
erikchene50acd882015-11-24 18:28:48579 if (globals->message_logging)
580 LOG(INFO) << "Privileged process finishing callback.";
erikchenb82097cc2015-10-12 23:27:55581 listener.pop_first_message();
582 }
583 }
584
585 if (active_names_at_start != IPC::GetActiveNameCount()) {
586 LOG(INFO) << "Memory leak!.";
587 }
588 LOG(INFO) << "Privileged process end.";
589 return 0;
590}
591
592// An unprivileged process makes a shared memory region, and writes a string to
593// it. The SharedMemoryHandle is sent to the privileged process using Chrome
594// IPC. The privileged process checks that it received the same memory region.
595TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54596 // Mach-based SharedMemory isn't support on OSX 10.6.
597 if (base::mac::IsOSSnowLeopard())
598 return;
599
erikchenb82097cc2015-10-12 23:27:55600 CommonSetUp("SendSharedMemoryHandle");
601
602 SendMessage1(kDataBuffer1);
603 base::MessageLoop::current()->Run();
604 CommonTearDown();
605}
606
607void SendSharedMemoryHandleCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27608 const IPC::Message& message,
609 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55610 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
611 SendControlMessage(sender, success);
612}
613
614MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
615 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
616 "SendSharedMemoryHandle");
617}
618
619// Similar to SendSharedMemoryHandle, but sends a very long shared memory
620// region.
621TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
erikchen328bf3f2015-10-24 00:46:54622 // Mach-based SharedMemory isn't support on OSX 10.6.
623 if (base::mac::IsOSSnowLeopard())
624 return;
625
erikchenb82097cc2015-10-12 23:27:55626 CommonSetUp("SendSharedMemoryHandleLong");
627
628 std::string buffer(1 << 23, 'a');
629 SendMessage1(buffer);
630 base::MessageLoop::current()->Run();
631 CommonTearDown();
632}
633
634void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27635 const IPC::Message& message,
636 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55637 std::string buffer(1 << 23, 'a');
638 bool success = CheckContentsOfMessage1(message, buffer);
639 SendControlMessage(sender, success);
640}
641
642MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
643 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
644 "SendSharedMemoryHandleLong");
645}
646
647// Similar to SendSharedMemoryHandle, but sends two different shared memory
648// regions in two messages.
649TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54650 // Mach-based SharedMemory isn't support on OSX 10.6.
651 if (base::mac::IsOSSnowLeopard())
652 return;
653
erikchenb82097cc2015-10-12 23:27:55654 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
655
656 SendMessage1(kDataBuffer1);
657 SendMessage1(kDataBuffer2);
658 base::MessageLoop::current()->Run();
659 CommonTearDown();
660}
661
662void SendTwoMessagesDifferentSharedMemoryHandleCallback(
663 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27664 const IPC::Message& message,
665 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55666 static int count = 0;
667 static bool success = true;
668 ++count;
669 if (count == 1) {
670 success &= CheckContentsOfMessage1(message, kDataBuffer1);
671 } else if (count == 2) {
672 success &= CheckContentsOfMessage1(message, kDataBuffer2);
673 SendControlMessage(sender, success);
674 }
675}
676
677MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
678 return CommonPrivilegedProcessMain(
679 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
680 "SendTwoMessagesDifferentSharedMemoryHandle");
681}
682
683// Similar to SendSharedMemoryHandle, but sends the same shared memory region in
684// two messages.
685TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
erikchen328bf3f2015-10-24 00:46:54686 // Mach-based SharedMemory isn't support on OSX 10.6.
687 if (base::mac::IsOSSnowLeopard())
688 return;
689
erikchenb82097cc2015-10-12 23:27:55690 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
691
692 {
693 scoped_ptr<base::SharedMemory> shared_memory(
694 MakeSharedMemory(kDataBuffer1));
695
696 for (int i = 0; i < 2; ++i) {
697 IPC::Message* message =
698 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
699 sender()->Send(message);
700 }
701 }
702
703 base::MessageLoop::current()->Run();
704 CommonTearDown();
705}
706
707void SendTwoMessagesSameSharedMemoryHandleCallback(
708 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27709 const IPC::Message& message,
710 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55711 static int count = 0;
712 static base::SharedMemoryHandle handle1;
713 ++count;
714
715 if (count == 1) {
716 handle1 = GetSharedMemoryHandleFromMsg1(message);
717 } else if (count == 2) {
718 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
719
720 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
721 handle1, handle2, kDataBuffer1);
722 SendControlMessage(sender, success);
723 }
724}
725
726MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
727 return CommonPrivilegedProcessMain(
728 &SendTwoMessagesSameSharedMemoryHandleCallback,
729 "SendTwoMessagesSameSharedMemoryHandle");
730}
731
732// Similar to SendSharedMemoryHandle, but sends one message with two different
733// memory regions.
734TEST_F(IPCAttachmentBrokerMacTest,
735 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
erikchen328bf3f2015-10-24 00:46:54736 // Mach-based SharedMemory isn't support on OSX 10.6.
737 if (base::mac::IsOSSnowLeopard())
738 return;
739
erikchenb82097cc2015-10-12 23:27:55740 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
741
742 {
743 scoped_ptr<base::SharedMemory> shared_memory1(
744 MakeSharedMemory(kDataBuffer1));
745 scoped_ptr<base::SharedMemory> shared_memory2(
746 MakeSharedMemory(kDataBuffer2));
747 IPC::Message* message = new TestSharedMemoryHandleMsg2(
748 shared_memory1->handle(), shared_memory2->handle());
749 sender()->Send(message);
750 }
751 base::MessageLoop::current()->Run();
752 CommonTearDown();
753}
754
755void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
756 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27757 const IPC::Message& message,
758 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55759 base::SharedMemoryHandle handle1;
760 base::SharedMemoryHandle handle2;
761 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
762 LOG(ERROR) << "Failed to deserialize message.";
763 SendControlMessage(sender, false);
764 return;
765 }
766
767 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
768 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
769 SendControlMessage(sender, success);
770}
771
772MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
773 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
774 return CommonPrivilegedProcessMain(
775 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
776 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
777}
778
779// Similar to SendSharedMemoryHandle, but sends one message that contains the
780// same memory region twice.
781TEST_F(IPCAttachmentBrokerMacTest,
782 SendOneMessageWithTwoSameSharedMemoryHandles) {
erikchen328bf3f2015-10-24 00:46:54783 // Mach-based SharedMemory isn't support on OSX 10.6.
784 if (base::mac::IsOSSnowLeopard())
785 return;
786
erikchenb82097cc2015-10-12 23:27:55787 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
788
789 {
790 scoped_ptr<base::SharedMemory> shared_memory(
791 MakeSharedMemory(kDataBuffer1));
792 IPC::Message* message = new TestSharedMemoryHandleMsg2(
793 shared_memory->handle(), shared_memory->handle());
794 sender()->Send(message);
795 }
796 base::MessageLoop::current()->Run();
797 CommonTearDown();
798}
799
800void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
801 IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27802 const IPC::Message& message,
803 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55804 base::SharedMemoryHandle handle1;
805 base::SharedMemoryHandle handle2;
806 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
807 LOG(ERROR) << "Failed to deserialize message.";
808 SendControlMessage(sender, false);
809 return;
810 }
811
812 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
813 handle1, handle2, kDataBuffer1);
814 SendControlMessage(sender, success);
815}
816
817MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
818 SendOneMessageWithTwoSameSharedMemoryHandles) {
819 return CommonPrivilegedProcessMain(
820 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
821 "SendOneMessageWithTwoSameSharedMemoryHandles");
822}
823
824// Sends one message with two Posix FDs and two Mach ports.
825TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
erikchen328bf3f2015-10-24 00:46:54826 // Mach-based SharedMemory isn't support on OSX 10.6.
827 if (base::mac::IsOSSnowLeopard())
828 return;
829
erikchenb82097cc2015-10-12 23:27:55830 base::ScopedTempDir temp_dir;
831 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
832 base::FilePath fp1, fp2;
833 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp1));
834 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &fp2));
835
836 CommonSetUp("SendPosixFDAndMachPort");
837
838 {
839 scoped_ptr<base::SharedMemory> shared_memory1(
840 MakeSharedMemory(kDataBuffer1));
841 scoped_ptr<base::SharedMemory> shared_memory2(
842 MakeSharedMemory(kDataBuffer2));
843
844 base::FileDescriptor file_descriptor1(
845 MakeFileDescriptor(fp1, kDataBuffer3));
846 base::FileDescriptor file_descriptor2(
847 MakeFileDescriptor(fp2, kDataBuffer4));
848
849 IPC::Message* message = new TestSharedMemoryHandleMsg3(
850 file_descriptor1, shared_memory1->handle(), file_descriptor2,
851 shared_memory2->handle());
852 sender()->Send(message);
853 }
854
855 base::MessageLoop::current()->Run();
856 CommonTearDown();
857}
858
859void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27860 const IPC::Message& message,
861 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55862 TestSharedMemoryHandleMsg3::Schema::Param p;
863 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
864 LOG(ERROR) << "Failed to deserialize message.";
865 SendControlMessage(sender, false);
866 return;
867 }
868
869 base::SharedMemoryHandle handle1 = base::get<1>(p);
870 base::SharedMemoryHandle handle2 = base::get<3>(p);
871 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
872 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
873 if (!success1)
874 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
875
876 bool success2 =
877 CheckContentsOfFileDescriptor(base::get<0>(p), kDataBuffer3) &&
878 CheckContentsOfFileDescriptor(base::get<2>(p), kDataBuffer4);
879 if (!success2)
880 LOG(ERROR) << "FileDescriptors have wrong contents.";
881
882 SendControlMessage(sender, success1 && success2);
883}
884
885MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
886 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
887 "SendPosixFDAndMachPort");
888}
889
890// Similar to SendHandle, except the attachment's destination process is this
891// process. This is an unrealistic scenario, but simulates an unprivileged
892// process sending an attachment to another unprivileged process.
893TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
erikchen328bf3f2015-10-24 00:46:54894 // Mach-based SharedMemory isn't support on OSX 10.6.
895 if (base::mac::IsOSSnowLeopard())
896 return;
897
erikchenb82097cc2015-10-12 23:27:55898 SetBroker(new MockBroker);
899 CommonSetUp("SendSharedMemoryHandleToSelf");
900
901 // Technically, the channel is an endpoint, but we need the proxy listener to
902 // receive the messages so that it can quit the message loop.
903 channel()->SetAttachmentBrokerEndpoint(false);
904 get_proxy_listener()->set_listener(get_broker());
905
906 {
907 scoped_ptr<base::SharedMemory> shared_memory(
908 MakeSharedMemory(kDataBuffer1));
909 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
910 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
911
912 IPC::Message* message =
913 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
914 sender()->Send(message);
erikchen94c9b702015-11-06 21:12:36915
916 // Wait until the child process has sent this process a message.
erikchenb82097cc2015-10-12 23:27:55917 base::MessageLoop::current()->Run();
918
erikchen94c9b702015-11-06 21:12:36919 // Wait for any asynchronous activity to complete.
920 base::MessageLoop::current()->RunUntilIdle();
921
erikchenb82097cc2015-10-12 23:27:55922 // Get the received attachment.
923 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
erikchen94c9b702015-11-06 21:12:36924 ASSERT_TRUE(id);
erikchenb82097cc2015-10-12 23:27:55925 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
926 get_broker()->GetAttachmentWithId(*id, &received_attachment);
927 ASSERT_NE(received_attachment.get(), nullptr);
928
929 // Check that it's has the same name, but that the ref count has increased.
930 base::mac::ScopedMachSendRight memory_object(
931 GetMachPortFromBrokeredAttachment(received_attachment));
932 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
933 EXPECT_EQ(ref_count + 1,
934 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
935 MACH_PORT_RIGHT_SEND));
936 }
937
938 FinalCleanUp();
939}
940
941void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27942 const IPC::Message&,
943 ChildProcessGlobals* globals) {
erikchenb82097cc2015-10-12 23:27:55944 // Do nothing special. The default behavior already runs the
945 // AttachmentBrokerPrivilegedMac.
946}
947
948MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
949 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
950 "SendSharedMemoryHandleToSelf");
951}
952
erikchen24e44d32015-10-21 22:28:54953// Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
954// Channel.
955TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
erikchen328bf3f2015-10-24 00:46:54956 // Mach-based SharedMemory isn't support on OSX 10.6.
957 if (base::mac::IsOSSnowLeopard())
958 return;
959
erikchen24e44d32015-10-21 22:28:54960 Init("SendSharedMemoryHandleChannelProxy");
961 MachPreForkSetUp();
962
963 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
erikchen94c9b702015-11-06 21:12:36964 get_broker()->AddObserver(get_observer(), task_runner());
erikchen24e44d32015-10-21 22:28:54965
966 scoped_ptr<base::Thread> thread(
967 new base::Thread("ChannelProxyTestServerThread"));
968 base::Thread::Options options;
969 options.message_loop_type = base::MessageLoop::TYPE_IO;
970 thread->StartWithOptions(options);
971
972 CreateChannelProxy(get_proxy_listener(), thread->task_runner().get());
973 get_broker()->DesignateBrokerCommunicationChannel(channel_proxy());
974
975 ASSERT_TRUE(StartClient());
976
977 MachPostForkSetUp();
978 active_names_at_start_ = IPC::GetActiveNameCount();
979 get_proxy_listener()->set_listener(get_result_listener());
980
981 SendMessage1(kDataBuffer1);
982 base::MessageLoop::current()->Run();
983
984 CheckChildResult();
985
986 // There should be no leaked names.
987 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
988
989 // Close the channel so the client's OnChannelError() gets fired.
990 channel_proxy()->Close();
991
992 EXPECT_TRUE(WaitForClientShutdown());
993 DestroyChannelProxy();
994}
995
996void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:27997 const IPC::Message& message,
998 ChildProcessGlobals* globals) {
erikchen24e44d32015-10-21 22:28:54999 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
1000 SendControlMessage(sender, success);
1001}
1002
1003MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
1004 return CommonPrivilegedProcessMain(
1005 &SendSharedMemoryHandleChannelProxyCallback,
1006 "SendSharedMemoryHandleChannelProxy");
1007}
1008
erikchen328bf3f2015-10-24 00:46:541009// Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
1010// ShareToProcess().
1011TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
1012 // Mach-based SharedMemory isn't support on OSX 10.6.
1013 if (base::mac::IsOSSnowLeopard())
1014 return;
1015
1016 CommonSetUp("ShareToProcess");
1017
1018 {
1019 scoped_ptr<base::SharedMemory> shared_memory(
1020 MakeSharedMemory(kDataBuffer1));
1021 base::SharedMemoryHandle new_handle;
1022 ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
1023 IPC::Message* message =
1024 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1025 sender()->Send(message);
1026 }
1027
1028 base::MessageLoop::current()->Run();
1029 CommonTearDown();
1030}
1031
erikchen7c556432015-11-11 22:07:271032void ShareToProcessCallback(IPC::Sender* sender,
1033 const IPC::Message& message,
1034 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541035 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
1036 SendControlMessage(sender, success);
1037}
1038
1039MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
1040 return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
1041}
1042
1043// Similar to ShareToProcess, but instead shares the memory object only with
1044// read permissions.
1045TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
1046 // Mach-based SharedMemory isn't support on OSX 10.6.
1047 if (base::mac::IsOSSnowLeopard())
1048 return;
1049
1050 CommonSetUp("ShareReadOnlyToProcess");
1051
1052 {
1053 scoped_ptr<base::SharedMemory> shared_memory(
1054 MakeSharedMemory(kDataBuffer1));
1055 base::SharedMemoryHandle new_handle;
1056 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
1057 IPC::Message* message =
1058 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1059 sender()->Send(message);
1060 }
1061
1062 base::MessageLoop::current()->Run();
1063 CommonTearDown();
1064}
1065
1066void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
erikchen7c556432015-11-11 22:07:271067 const IPC::Message& message,
1068 ChildProcessGlobals* globals) {
erikchen328bf3f2015-10-24 00:46:541069 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1070
1071 // Try to map the memory as writable.
1072 scoped_ptr<base::SharedMemory> shared_memory(
1073 MapSharedMemoryHandle(shm, false));
1074 ASSERT_EQ(nullptr, shared_memory->memory());
1075
1076 // Now try as read-only.
1077 scoped_ptr<base::SharedMemory> shared_memory2(
1078 MapSharedMemoryHandle(shm.Duplicate(), true));
1079 int current_prot, max_prot;
1080 ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
1081 shared_memory2->mapped_size(),
1082 &current_prot, &max_prot));
1083 ASSERT_EQ(VM_PROT_READ, current_prot);
1084 ASSERT_EQ(VM_PROT_READ, max_prot);
1085
1086 bool success =
1087 memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
1088 SendControlMessage(sender, success);
1089}
1090
1091MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
1092 return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
1093 "ShareReadOnlyToProcess");
1094}
1095
erikchen7c556432015-11-11 22:07:271096// Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
1097// not have the task port for the parent process.
1098TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
1099 // Mach-based SharedMemory isn't support on OSX 10.6.
1100 if (base::mac::IsOSSnowLeopard())
1101 return;
1102
1103 SetBroker(new MockBroker);
1104 CommonSetUp("SendSharedMemoryHandleToSelfDelayedPort");
1105
1106 // Technically, the channel is an endpoint, but we need the proxy listener to
1107 // receive the messages so that it can quit the message loop.
1108 channel()->SetAttachmentBrokerEndpoint(false);
1109 get_proxy_listener()->set_listener(get_broker());
1110
1111 {
1112 scoped_ptr<base::SharedMemory> shared_memory(
1113 MakeSharedMemory(kDataBuffer1));
1114 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
1115 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
1116
1117 std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
1118 const int kMessagesToTest = 3;
1119 for (int i = 0; i < kMessagesToTest; ++i) {
1120 base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
1121 ids.push_back(
1122 IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
1123 IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
1124 h.GetMemoryObject(), getpid(), ids[i]);
1125 sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
1126
1127 // Send a dummy message, which will trigger the callback handler in the
1128 // child process.
1129 sender()->Send(new TestSharedMemoryHandleMsg4(1));
1130 }
1131
1132 int received_message_count = 0;
1133 while (received_message_count < kMessagesToTest) {
1134 // Wait until the child process has sent this process a message.
1135 base::MessageLoop::current()->Run();
1136
1137 // Wait for any asynchronous activity to complete.
1138 base::MessageLoop::current()->RunUntilIdle();
1139
1140 while (get_proxy_listener()->has_message()) {
1141 get_proxy_listener()->pop_first_message();
1142 received_message_count++;
1143 }
1144 }
1145
1146 for (int i = 0; i < kMessagesToTest; ++i) {
1147 IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
1148 ASSERT_TRUE(id);
1149 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
1150 get_broker()->GetAttachmentWithId(*id, &received_attachment);
1151 ASSERT_NE(received_attachment.get(), nullptr);
1152
1153 base::mac::ScopedMachSendRight memory_object(
1154 GetMachPortFromBrokeredAttachment(received_attachment));
1155 ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
1156 }
1157
1158 // Check that the ref count hasn't changed.
1159 EXPECT_EQ(ref_count,
1160 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
1161 MACH_PORT_RIGHT_SEND));
1162 }
1163
1164 FinalCleanUp();
1165}
1166
1167void SendSharedMemoryHandleToSelfDelayedPortCallback(
1168 IPC::Sender* sender,
1169 const IPC::Message& message,
1170 ChildProcessGlobals* globals) {
1171 static int i = 0;
1172 static base::ProcessId pid = message.get_sender_pid();
1173 static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
1174 ++i;
1175
1176 if (i == 1) {
1177 // Pretend to not have the task port for the parent.
1178 globals->port_provider.ClearPortMap();
1179 } else if (i == 2) {
1180 // Intentionally do nothing.
1181 } else if (i == 3) {
1182 // Setting the task port should trigger callbacks, eventually resulting in
1183 // multiple attachment broker messages.
1184 globals->port_provider.InsertEntry(pid, task_port);
1185 }
1186}
1187
1188MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
1189 return CommonPrivilegedProcessMain(
1190 &SendSharedMemoryHandleToSelfDelayedPortCallback,
1191 "SendSharedMemoryHandleToSelfDelayedPort");
1192}
1193
erikchene50acd882015-11-24 18:28:481194// Tests the memory usage characteristics of attachment brokering a single large
1195// message. This test has the *potential* to be flaky, since it compares
1196// resident memory at different points in time, and that measurement is
1197// non-deterministic.
1198TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) {
1199 // Mach-based SharedMemory isn't support on OSX 10.6.
1200 if (base::mac::IsOSSnowLeopard())
1201 return;
1202
1203 CommonSetUp("MemoryUsageLargeMessage");
1204
1205 std::string test_string(g_large_message_size, 'a');
1206 SendMessage1(test_string);
1207 base::MessageLoop::current()->Run();
1208 CommonTearDown();
1209}
1210
1211void MemoryUsageLargeMessageCallback(IPC::Sender* sender,
1212 const IPC::Message& message,
1213 ChildProcessGlobals* globals) {
1214 EXPECT_LE(GetResidentSize(),
1215 globals->initial_resident_size + g_expected_memory_increase);
1216
1217 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1218 scoped_ptr<base::SharedMemory> shared_memory(
1219 MapSharedMemoryHandle(shm, false));
1220 EXPECT_LE(GetResidentSize(),
1221 globals->initial_resident_size + g_expected_memory_increase);
1222
1223 char* addr = static_cast<char*>(shared_memory->memory());
1224 for (size_t i = 0; i < g_large_message_size; i += 1024) {
1225 addr[i] = 'a';
1226 }
1227 EXPECT_GE(GetResidentSize(),
1228 globals->initial_resident_size + g_large_message_size);
1229
1230 shared_memory.reset();
1231#if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
1232 !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
1233 !defined(UNDEFINED_SANITIZER)
1234 // Under a sanitizer build, releasing memory does not necessarily reduce the
1235 // amount of resident memory.
1236 EXPECT_LE(GetResidentSize(),
1237 globals->initial_resident_size + g_expected_memory_increase);
1238#endif
1239
1240 SendControlMessage(sender, true);
1241}
1242
1243MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) {
1244 return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback,
1245 "MemoryUsageLargeMessage");
1246}
1247
1248// Tests the memory usage characteristics of attachment brokering many small
1249// messages. This test has the *potential* to be flaky, since it compares
1250// resident memory at different points in time, and that measurement is
1251// non-deterministic.
1252TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) {
1253 // Mach-based SharedMemory isn't support on OSX 10.6.
1254 if (base::mac::IsOSSnowLeopard())
1255 return;
1256
1257 CommonSetUp("MemoryUsageManyMessages");
1258
1259 for (int i = 0; i < g_large_message_count; ++i) {
1260 std::string message = base::IntToString(i);
1261 message += '\0';
1262 size_t end = message.size();
1263 message.resize(g_medium_message_size);
1264 std::fill(message.begin() + end, message.end(), 'a');
1265 SendMessage1(message);
1266
1267 base::MessageLoop::current()->RunUntilIdle();
1268 }
1269
1270 if (get_result_listener()->get_result() == RESULT_UNKNOWN)
1271 base::MessageLoop::current()->Run();
1272
1273 CommonTearDown();
1274}
1275
1276void MemoryUsageManyMessagesCallback(IPC::Sender* sender,
1277 const IPC::Message& message,
1278 ChildProcessGlobals* globals) {
1279 static int message_index = 0;
1280
1281 {
1282 // Map the shared memory, and make sure that its pages are counting towards
1283 // resident size.
1284 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1285 scoped_ptr<base::SharedMemory> shared_memory(
1286 MapSharedMemoryHandle(shm, false));
1287
1288 char* addr = static_cast<char*>(shared_memory->memory());
1289 std::string message_string(addr);
1290 int message_int;
1291 ASSERT_TRUE(base::StringToInt(message_string, &message_int));
1292 ASSERT_EQ(message_index, message_int);
1293 for (size_t i = 0; i < g_medium_message_size; i += 1024) {
1294 addr[i] = 'a';
1295 }
1296 }
1297
1298 ++message_index;
1299
1300 if (message_index == 1) {
1301 // Disable message logging, since it significantly contributes towards total
1302 // memory usage.
1303 LOG(INFO) << "Disable privileged process message logging.";
1304 globals->message_logging = false;
1305 }
1306
1307 if (message_index == g_large_message_count) {
1308 size_t memory_increase_kb =
1309 (GetResidentSize() - globals->initial_resident_size) / 1024;
1310 LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb;
1311
1312#if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
1313 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
1314 defined(UNDEFINED_SANITIZER)
1315 // Under a sanitizer build, releasing memory does not necessarily reduce the
1316 // amount of resident memory.
1317 bool success = true;
1318#else
1319 // The total increase in resident size should be less than 1MB. The exact
1320 // amount is not deterministic.
1321 bool success = memory_increase_kb < 1024;
1322#endif
1323
1324 SendControlMessage(sender, success);
1325 }
1326}
1327
1328MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) {
1329 return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback,
1330 "MemoryUsageManyMessages");
1331}
1332
erikchenb82097cc2015-10-12 23:27:551333} // namespace