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