1 // Copyright 2016 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 <stdint.h> 6 #include <string.h> 7 8 #include <algorithm> 9 #include <string> 10 #include <vector> 11 12 #include "base/files/file.h" 13 #include "base/files/file_util.h" 14 #include "base/memory/shared_memory.h" 15 #include "base/process/process_handle.h" 16 #include "build/build_config.h" 17 #include "mojo/core/test/mojo_test_base.h" 18 #include "mojo/public/c/system/platform_handle.h" 19 #include "mojo/public/cpp/system/message_pipe.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 #if defined(OS_WIN) 23 #include <windows.h> 24 #endif 25 26 #if defined(OS_WIN) 27 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE 28 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 29 #define SIMPLE_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR 30 #endif 31 32 #if defined(OS_FUCHSIA) 33 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE \ 34 MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE 35 #elif defined(OS_MACOSX) && !defined(OS_IOS) 36 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT 37 #elif defined(OS_WIN) || defined(OS_POSIX) 38 #define SHARED_BUFFER_PLATFORM_HANDLE_TYPE SIMPLE_PLATFORM_HANDLE_TYPE 39 #endif 40 41 uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) { 42 #if defined(OS_WIN) 43 return reinterpret_cast<uint64_t>(file); 44 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 45 return static_cast<uint64_t>(file); 46 #endif 47 } 48 49 base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) { 50 #if defined(OS_WIN) 51 return reinterpret_cast<base::PlatformFile>(value); 52 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 53 return static_cast<base::PlatformFile>(value); 54 #endif 55 } 56 57 namespace mojo { 58 namespace core { 59 namespace { 60 61 using PlatformWrapperTest = test::MojoTestBase; 62 63 TEST_F(PlatformWrapperTest, WrapPlatformHandle) { 64 // Create a temporary file and write a message to it. 65 base::FilePath temp_file_path; 66 ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path)); 67 const std::string kMessage = "Hello, world!"; 68 EXPECT_EQ(base::WriteFile(temp_file_path, kMessage.data(), 69 static_cast<int>(kMessage.size())), 70 static_cast<int>(kMessage.size())); 71 72 RunTestClient("ReadPlatformFile", [&](MojoHandle h) { 73 // Open the temporary file for reading, wrap its handle, and send it to 74 // the child along with the expected message to be read. 75 base::File file(temp_file_path, 76 base::File::FLAG_OPEN | base::File::FLAG_READ); 77 EXPECT_TRUE(file.IsValid()); 78 79 MojoHandle wrapped_handle; 80 MojoPlatformHandle os_file; 81 os_file.struct_size = sizeof(MojoPlatformHandle); 82 os_file.type = SIMPLE_PLATFORM_HANDLE_TYPE; 83 os_file.value = 84 PlatformHandleValueFromPlatformFile(file.TakePlatformFile()); 85 EXPECT_EQ(MOJO_RESULT_OK, 86 MojoWrapPlatformHandle(&os_file, nullptr, &wrapped_handle)); 87 88 WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1); 89 }); 90 91 base::DeleteFile(temp_file_path, false); 92 } 93 94 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile, PlatformWrapperTest, h) { 95 // Read a message and a wrapped file handle; unwrap the handle. 96 MojoHandle wrapped_handle; 97 std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1); 98 99 MojoPlatformHandle platform_handle; 100 platform_handle.struct_size = sizeof(MojoPlatformHandle); 101 ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformHandle(wrapped_handle, nullptr, 102 &platform_handle)); 103 EXPECT_EQ(SIMPLE_PLATFORM_HANDLE_TYPE, platform_handle.type); 104 base::File file(PlatformFileFromPlatformHandleValue(platform_handle.value)); 105 106 // Expect to read the same message from the file. 107 std::vector<char> data(message.size()); 108 EXPECT_EQ(file.ReadAtCurrentPos(data.data(), static_cast<int>(data.size())), 109 static_cast<int>(data.size())); 110 EXPECT_TRUE(std::equal(message.begin(), message.end(), data.begin())); 111 } 112 113 TEST_F(PlatformWrapperTest, WrapPlatformSharedMemoryRegion) { 114 // Allocate a new platform shared buffer and write a message into it. 115 const std::string kMessage = "Hello, world!"; 116 base::SharedMemory buffer; 117 buffer.CreateAndMapAnonymous(kMessage.size()); 118 CHECK(buffer.memory()); 119 memcpy(buffer.memory(), kMessage.data(), kMessage.size()); 120 121 RunTestClient("ReadPlatformSharedBuffer", [&](MojoHandle h) { 122 // Wrap the shared memory handle and send it to the child along with the 123 // expected message. 124 base::SharedMemoryHandle memory_handle = 125 base::SharedMemory::DuplicateHandle(buffer.handle()); 126 MojoPlatformHandle os_buffer; 127 os_buffer.struct_size = sizeof(MojoPlatformHandle); 128 os_buffer.type = SHARED_BUFFER_PLATFORM_HANDLE_TYPE; 129 #if defined(OS_WIN) 130 os_buffer.value = reinterpret_cast<uint64_t>(memory_handle.GetHandle()); 131 #elif defined(OS_MACOSX) && !defined(OS_IOS) 132 os_buffer.value = static_cast<uint64_t>(memory_handle.GetMemoryObject()); 133 #elif defined(OS_POSIX) || defined(OS_FUCHSIA) 134 os_buffer.value = static_cast<uint64_t>(memory_handle.GetHandle()); 135 #else 136 #error Unsupported platform 137 #endif 138 139 MojoSharedBufferGuid mojo_guid; 140 base::UnguessableToken guid = memory_handle.GetGUID(); 141 mojo_guid.high = guid.GetHighForSerialization(); 142 mojo_guid.low = guid.GetLowForSerialization(); 143 144 MojoHandle wrapped_handle; 145 ASSERT_EQ(MOJO_RESULT_OK, 146 MojoWrapPlatformSharedMemoryRegion( 147 &os_buffer, 1, kMessage.size(), &mojo_guid, 148 MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, 149 nullptr, &wrapped_handle)); 150 WriteMessageWithHandles(h, kMessage, &wrapped_handle, 1); 151 152 // As a sanity check, send the GUID explicitly in a second message. We'll 153 // verify that the deserialized buffer handle holds the same GUID on the 154 // receiving end. 155 WriteMessageRaw(MessagePipeHandle(h), &mojo_guid, sizeof(mojo_guid), 156 nullptr, 0, MOJO_WRITE_MESSAGE_FLAG_NONE); 157 }); 158 } 159 160 DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer, 161 PlatformWrapperTest, 162 h) { 163 // Read a message and a wrapped shared buffer handle. 164 MojoHandle wrapped_handle; 165 std::string message = ReadMessageWithHandles(h, &wrapped_handle, 1); 166 167 // Check the message in the buffer 168 ExpectBufferContents(wrapped_handle, 0, message); 169 170 // Now unwrap the buffer and verify that the base::SharedMemoryHandle also 171 // works as expected. 172 MojoPlatformHandle os_buffer; 173 os_buffer.struct_size = sizeof(MojoPlatformHandle); 174 uint32_t num_handles = 1; 175 uint64_t size; 176 MojoSharedBufferGuid mojo_guid; 177 MojoPlatformSharedMemoryRegionAccessMode access_mode; 178 ASSERT_EQ(MOJO_RESULT_OK, MojoUnwrapPlatformSharedMemoryRegion( 179 wrapped_handle, nullptr, &os_buffer, 180 &num_handles, &size, &mojo_guid, &access_mode)); 181 EXPECT_EQ(MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE, access_mode); 182 183 base::UnguessableToken guid = 184 base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low); 185 #if defined(OS_WIN) 186 ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE, os_buffer.type); 187 base::SharedMemoryHandle memory_handle( 188 reinterpret_cast<HANDLE>(os_buffer.value), size, guid); 189 #elif defined(OS_FUCHSIA) 190 ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE, os_buffer.type); 191 base::SharedMemoryHandle memory_handle( 192 static_cast<zx_handle_t>(os_buffer.value), size, guid); 193 #elif defined(OS_MACOSX) && !defined(OS_IOS) 194 ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT, os_buffer.type); 195 base::SharedMemoryHandle memory_handle( 196 static_cast<mach_port_t>(os_buffer.value), size, guid); 197 #elif defined(OS_POSIX) 198 ASSERT_EQ(MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR, os_buffer.type); 199 base::SharedMemoryHandle memory_handle( 200 base::FileDescriptor(static_cast<int>(os_buffer.value), false), size, 201 guid); 202 #endif 203 204 base::SharedMemory memory(memory_handle, false); 205 memory.Map(message.size()); 206 ASSERT_TRUE(memory.memory()); 207 208 EXPECT_TRUE(std::equal(message.begin(), message.end(), 209 static_cast<const char*>(memory.memory()))); 210 211 // Verify that the received buffer's internal GUID was preserved in transit. 212 EXPECT_EQ(MOJO_RESULT_OK, WaitForSignals(h, MOJO_HANDLE_SIGNAL_READABLE)); 213 std::vector<uint8_t> guid_bytes; 214 EXPECT_EQ(MOJO_RESULT_OK, 215 ReadMessageRaw(MessagePipeHandle(h), &guid_bytes, nullptr, 216 MOJO_READ_MESSAGE_FLAG_NONE)); 217 EXPECT_EQ(sizeof(MojoSharedBufferGuid), guid_bytes.size()); 218 auto* expected_guid = 219 reinterpret_cast<MojoSharedBufferGuid*>(guid_bytes.data()); 220 EXPECT_EQ(expected_guid->high, mojo_guid.high); 221 EXPECT_EQ(expected_guid->low, mojo_guid.low); 222 } 223 224 TEST_F(PlatformWrapperTest, InvalidHandle) { 225 // Wrap an invalid platform handle and expect to unwrap the same. 226 227 MojoHandle wrapped_handle; 228 MojoPlatformHandle invalid_handle; 229 invalid_handle.struct_size = sizeof(MojoPlatformHandle); 230 invalid_handle.type = MOJO_PLATFORM_HANDLE_TYPE_INVALID; 231 EXPECT_EQ(MOJO_RESULT_OK, 232 MojoWrapPlatformHandle(&invalid_handle, nullptr, &wrapped_handle)); 233 EXPECT_EQ(MOJO_RESULT_OK, 234 MojoUnwrapPlatformHandle(wrapped_handle, nullptr, &invalid_handle)); 235 EXPECT_EQ(MOJO_PLATFORM_HANDLE_TYPE_INVALID, invalid_handle.type); 236 } 237 238 TEST_F(PlatformWrapperTest, InvalidArgument) { 239 // Try to wrap an invalid MojoPlatformHandle struct and expect an error. 240 MojoHandle wrapped_handle; 241 MojoPlatformHandle platform_handle; 242 platform_handle.struct_size = 0; 243 EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, 244 MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle)); 245 } 246 247 } // namespace 248 } // namespace core 249 } // namespace mojo 250