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
PlatformHandleValueFromPlatformFile(base::PlatformFile file)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
PlatformFileFromPlatformHandleValue(uint64_t value)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
TEST_F(PlatformWrapperTest,WrapPlatformHandle)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
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformFile,PlatformWrapperTest,h)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
TEST_F(PlatformWrapperTest,WrapPlatformSharedMemoryRegion)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
DEFINE_TEST_CLIENT_TEST_WITH_PIPE(ReadPlatformSharedBuffer,PlatformWrapperTest,h)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
TEST_F(PlatformWrapperTest,InvalidHandle)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
TEST_F(PlatformWrapperTest,InvalidArgument)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