| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <mach/mach.h> | 5 #include <mach/mach.h> |
| 6 #include <mach/mach_vm.h> | 6 #include <mach/mach_vm.h> |
| 7 #include <servers/bootstrap.h> | 7 #include <servers/bootstrap.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 | 10 |
| 11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 12 #include "base/mac/mac_util.h" | 12 #include "base/mac/mac_util.h" |
| 13 #include "base/mac/mach_logging.h" | 13 #include "base/mac/mach_logging.h" |
| 14 #include "base/mac/scoped_mach_port.h" | 14 #include "base/mac/scoped_mach_port.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 17 #include "base/process/process_handle.h" | 17 #include "base/process/process_handle.h" |
| 18 #include "base/rand_util.h" | 18 #include "base/rand_util.h" |
| 19 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 20 #include "base/sys_info.h" | 20 #include "base/sys_info.h" |
| 21 #include "base/test/multiprocess_test.h" | 21 #include "base/test/multiprocess_test.h" |
| 22 #include "base/test/test_timeouts.h" | 22 #include "base/test/test_timeouts.h" |
| 23 #include "base/unguessable_token.h" |
| 23 #include "testing/multiprocess_func_list.h" | 24 #include "testing/multiprocess_func_list.h" |
| 24 | 25 |
| 25 namespace base { | 26 namespace base { |
| 26 | 27 |
| 27 namespace { | 28 namespace { |
| 28 | 29 |
| 29 // Gets the current and maximum protection levels of the memory region. | 30 // Gets the current and maximum protection levels of the memory region. |
| 30 // Returns whether the operation was successful. | 31 // Returns whether the operation was successful. |
| 31 // |current| and |max| are output variables only populated on success. | 32 // |current| and |max| are output variables only populated on success. |
| 32 bool GetProtections(void* address, size_t size, int* current, int* max) { | 33 bool GetProtections(void* address, size_t size, int* current, int* max) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 48 return false; | 49 return false; |
| 49 } | 50 } |
| 50 | 51 |
| 51 *current = basic_info.protection; | 52 *current = basic_info.protection; |
| 52 *max = basic_info.max_protection; | 53 *max = basic_info.max_protection; |
| 53 return true; | 54 return true; |
| 54 } | 55 } |
| 55 | 56 |
| 56 // Creates a new SharedMemory with the given |size|, filled with 'a'. | 57 // Creates a new SharedMemory with the given |size|, filled with 'a'. |
| 57 std::unique_ptr<SharedMemory> CreateSharedMemory(int size) { | 58 std::unique_ptr<SharedMemory> CreateSharedMemory(int size) { |
| 58 SharedMemoryHandle shm(size); | 59 SharedMemoryHandle shm(size, UnguessableToken::Create()); |
| 59 if (!shm.IsValid()) { | 60 if (!shm.IsValid()) { |
| 60 LOG(ERROR) << "Failed to make SharedMemoryHandle"; | 61 LOG(ERROR) << "Failed to make SharedMemoryHandle"; |
| 61 return nullptr; | 62 return nullptr; |
| 62 } | 63 } |
| 63 std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); | 64 std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); |
| 64 shared_memory->Map(size); | 65 shared_memory->Map(size); |
| 65 memset(shared_memory->memory(), 'a', size); | 66 memset(shared_memory->memory(), 'a', size); |
| 66 return shared_memory; | 67 return shared_memory; |
| 67 } | 68 } |
| 68 | 69 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 ASSERT_TRUE(spawn_child_.process.WaitForExitWithTimeout( | 241 ASSERT_TRUE(spawn_child_.process.WaitForExitWithTimeout( |
| 241 TestTimeouts::action_timeout(), &rv)); | 242 TestTimeouts::action_timeout(), &rv)); |
| 242 EXPECT_EQ(0, rv); | 243 EXPECT_EQ(0, rv); |
| 243 } | 244 } |
| 244 | 245 |
| 245 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) { | 246 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) { |
| 246 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); | 247 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); |
| 247 // The next mach port should be for a memory object. | 248 // The next mach port should be for a memory object. |
| 248 mach_port_t memory_object = ReceiveMachPort(client_port.get()); | 249 mach_port_t memory_object = ReceiveMachPort(client_port.get()); |
| 249 SharedMemoryHandle shm(memory_object, | 250 SharedMemoryHandle shm(memory_object, |
| 250 SharedMemoryMacMultiProcessTest::s_memory_size); | 251 SharedMemoryMacMultiProcessTest::s_memory_size, |
| 252 UnguessableToken::Create()); |
| 251 SharedMemory shared_memory(shm, false); | 253 SharedMemory shared_memory(shm, false); |
| 252 shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size); | 254 shared_memory.Map(SharedMemoryMacMultiProcessTest::s_memory_size); |
| 253 const char* start = static_cast<const char*>(shared_memory.memory()); | 255 const char* start = static_cast<const char*>(shared_memory.memory()); |
| 254 for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) { | 256 for (int i = 0; i < SharedMemoryMacMultiProcessTest::s_memory_size; ++i) { |
| 255 DCHECK_EQ(start[i], 'a'); | 257 DCHECK_EQ(start[i], 'a'); |
| 256 } | 258 } |
| 257 return 0; | 259 return 0; |
| 258 } | 260 } |
| 259 | 261 |
| 260 // Tests that mapping shared memory with an offset works correctly. | 262 // Tests that mapping shared memory with an offset works correctly. |
| 261 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) { | 263 TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) { |
| 262 SetUpChild("MachBasedSharedMemoryWithOffsetClient"); | 264 SetUpChild("MachBasedSharedMemoryWithOffsetClient"); |
| 263 | 265 |
| 264 SharedMemoryHandle shm(s_memory_size); | 266 SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); |
| 265 ASSERT_TRUE(shm.IsValid()); | 267 ASSERT_TRUE(shm.IsValid()); |
| 266 SharedMemory shared_memory(shm, false); | 268 SharedMemory shared_memory(shm, false); |
| 267 shared_memory.Map(s_memory_size); | 269 shared_memory.Map(s_memory_size); |
| 268 | 270 |
| 269 size_t page_size = SysInfo::VMAllocationGranularity(); | 271 size_t page_size = SysInfo::VMAllocationGranularity(); |
| 270 char* start = static_cast<char*>(shared_memory.memory()); | 272 char* start = static_cast<char*>(shared_memory.memory()); |
| 271 memset(start, 'a', page_size); | 273 memset(start, 'a', page_size); |
| 272 memset(start + page_size, 'b', page_size); | 274 memset(start + page_size, 'b', page_size); |
| 273 memset(start + 2 * page_size, 'c', page_size); | 275 memset(start + 2 * page_size, 'c', page_size); |
| 274 | 276 |
| 275 // Send the underlying memory object to the client process. | 277 // Send the underlying memory object to the client process. |
| 276 SendMachPort( | 278 SendMachPort( |
| 277 client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND); | 279 client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND); |
| 278 int rv = -1; | 280 int rv = -1; |
| 279 ASSERT_TRUE(spawn_child_.process.WaitForExitWithTimeout( | 281 ASSERT_TRUE(spawn_child_.process.WaitForExitWithTimeout( |
| 280 TestTimeouts::action_timeout(), &rv)); | 282 TestTimeouts::action_timeout(), &rv)); |
| 281 EXPECT_EQ(0, rv); | 283 EXPECT_EQ(0, rv); |
| 282 } | 284 } |
| 283 | 285 |
| 284 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) { | 286 MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) { |
| 285 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); | 287 mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp()); |
| 286 // The next mach port should be for a memory object. | 288 // The next mach port should be for a memory object. |
| 287 mach_port_t memory_object = ReceiveMachPort(client_port.get()); | 289 mach_port_t memory_object = ReceiveMachPort(client_port.get()); |
| 288 SharedMemoryHandle shm(memory_object, | 290 SharedMemoryHandle shm(memory_object, |
| 289 SharedMemoryMacMultiProcessTest::s_memory_size); | 291 SharedMemoryMacMultiProcessTest::s_memory_size, |
| 292 UnguessableToken::Create()); |
| 290 SharedMemory shared_memory(shm, false); | 293 SharedMemory shared_memory(shm, false); |
| 291 size_t page_size = SysInfo::VMAllocationGranularity(); | 294 size_t page_size = SysInfo::VMAllocationGranularity(); |
| 292 shared_memory.MapAt(page_size, 2 * page_size); | 295 shared_memory.MapAt(page_size, 2 * page_size); |
| 293 const char* start = static_cast<const char*>(shared_memory.memory()); | 296 const char* start = static_cast<const char*>(shared_memory.memory()); |
| 294 for (size_t i = 0; i < page_size; ++i) { | 297 for (size_t i = 0; i < page_size; ++i) { |
| 295 DCHECK_EQ(start[i], 'b'); | 298 DCHECK_EQ(start[i], 'b'); |
| 296 } | 299 } |
| 297 for (size_t i = page_size; i < 2 * page_size; ++i) { | 300 for (size_t i = page_size; i < 2 * page_size; ++i) { |
| 298 DCHECK_EQ(start[i], 'c'); | 301 DCHECK_EQ(start[i], 'c'); |
| 299 } | 302 } |
| 300 return 0; | 303 return 0; |
| 301 } | 304 } |
| 302 | 305 |
| 303 // Tests that duplication and closing has the right effect on Mach reference | 306 // Tests that duplication and closing has the right effect on Mach reference |
| 304 // counts. | 307 // counts. |
| 305 TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) { | 308 TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) { |
| 306 mach_msg_type_number_t active_name_count = GetActiveNameCount(); | 309 mach_msg_type_number_t active_name_count = GetActiveNameCount(); |
| 307 | 310 |
| 308 // Making a new SharedMemoryHandle increments the name count. | 311 // Making a new SharedMemoryHandle increments the name count. |
| 309 SharedMemoryHandle shm(s_memory_size); | 312 SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); |
| 310 ASSERT_TRUE(shm.IsValid()); | 313 ASSERT_TRUE(shm.IsValid()); |
| 311 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); | 314 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); |
| 312 | 315 |
| 313 // Duplicating the SharedMemoryHandle increments the ref count, but doesn't | 316 // Duplicating the SharedMemoryHandle increments the ref count, but doesn't |
| 314 // make a new name. | 317 // make a new name. |
| 315 shm.Duplicate(); | 318 shm.Duplicate(); |
| 316 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); | 319 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); |
| 317 | 320 |
| 318 // Closing the SharedMemoryHandle decrements the ref count. The first time has | 321 // Closing the SharedMemoryHandle decrements the ref count. The first time has |
| 319 // no effect. | 322 // no effect. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 338 EXPECT_EQ(active_name_count, GetActiveNameCount()); | 341 EXPECT_EQ(active_name_count, GetActiveNameCount()); |
| 339 } | 342 } |
| 340 | 343 |
| 341 // Tests that passing a SharedMemoryHandle to a SharedMemory object also passes | 344 // Tests that passing a SharedMemoryHandle to a SharedMemory object also passes |
| 342 // ownership, and that destroying the SharedMemory closes the SharedMemoryHandle | 345 // ownership, and that destroying the SharedMemory closes the SharedMemoryHandle |
| 343 // as well. | 346 // as well. |
| 344 TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) { | 347 TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) { |
| 345 mach_msg_type_number_t active_name_count = GetActiveNameCount(); | 348 mach_msg_type_number_t active_name_count = GetActiveNameCount(); |
| 346 | 349 |
| 347 // Making a new SharedMemoryHandle increments the name count. | 350 // Making a new SharedMemoryHandle increments the name count. |
| 348 SharedMemoryHandle shm(s_memory_size); | 351 SharedMemoryHandle shm(s_memory_size, UnguessableToken::Create()); |
| 349 ASSERT_TRUE(shm.IsValid()); | 352 ASSERT_TRUE(shm.IsValid()); |
| 350 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); | 353 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); |
| 351 | 354 |
| 352 // Name count doesn't change when mapping the memory. | 355 // Name count doesn't change when mapping the memory. |
| 353 std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); | 356 std::unique_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false)); |
| 354 shared_memory->Map(s_memory_size); | 357 shared_memory->Map(s_memory_size); |
| 355 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); | 358 EXPECT_EQ(active_name_count + 1, GetActiveNameCount()); |
| 356 | 359 |
| 357 // Destroying the SharedMemory object frees the resource. | 360 // Destroying the SharedMemory object frees the resource. |
| 358 shared_memory.reset(); | 361 shared_memory.reset(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 int current_prot, max_prot; | 404 int current_prot, max_prot; |
| 402 ASSERT_TRUE(GetProtections(shared_memory->memory(), | 405 ASSERT_TRUE(GetProtections(shared_memory->memory(), |
| 403 shared_memory->mapped_size(), ¤t_prot, | 406 shared_memory->mapped_size(), ¤t_prot, |
| 404 &max_prot)); | 407 &max_prot)); |
| 405 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot); | 408 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot); |
| 406 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot); | 409 ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot); |
| 407 | 410 |
| 408 // Make a new memory object. | 411 // Make a new memory object. |
| 409 SharedMemoryHandle shm2 = shared_memory->GetReadOnlyHandle(); | 412 SharedMemoryHandle shm2 = shared_memory->GetReadOnlyHandle(); |
| 410 ASSERT_TRUE(shm2.IsValid()); | 413 ASSERT_TRUE(shm2.IsValid()); |
| 414 EXPECT_EQ(shared_memory->handle().GetGUID(), shm2.GetGUID()); |
| 411 | 415 |
| 412 // Mapping with |readonly| set to |false| should fail. | 416 // Mapping with |readonly| set to |false| should fail. |
| 413 SharedMemory shared_memory2(shm2, false); | 417 SharedMemory shared_memory2(shm2, false); |
| 414 shared_memory2.Map(s_memory_size); | 418 shared_memory2.Map(s_memory_size); |
| 415 ASSERT_EQ(nullptr, shared_memory2.memory()); | 419 ASSERT_EQ(nullptr, shared_memory2.memory()); |
| 416 | 420 |
| 417 // Now trying mapping with |readonly| set to |true|. | 421 // Now trying mapping with |readonly| set to |true|. |
| 418 SharedMemory shared_memory3(shm2.Duplicate(), true); | 422 SharedMemory shared_memory3(shm2.Duplicate(), true); |
| 419 shared_memory3.Map(s_memory_size); | 423 shared_memory3.Map(s_memory_size); |
| 420 ASSERT_NE(nullptr, shared_memory3.memory()); | 424 ASSERT_NE(nullptr, shared_memory3.memory()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 444 | 448 |
| 445 // Intentionally map with |readonly| set to |false|. | 449 // Intentionally map with |readonly| set to |false|. |
| 446 SharedMemory shared_memory2(shm2, false); | 450 SharedMemory shared_memory2(shm2, false); |
| 447 shared_memory2.Map(s_memory_size); | 451 shared_memory2.Map(s_memory_size); |
| 448 } | 452 } |
| 449 | 453 |
| 450 EXPECT_EQ(active_name_count, GetActiveNameCount()); | 454 EXPECT_EQ(active_name_count, GetActiveNameCount()); |
| 451 } | 455 } |
| 452 | 456 |
| 453 } // namespace base | 457 } // namespace base |
| OLD | NEW |