• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "mojo/public/cpp/system/platform_handle.h"
6 
7 #include "base/memory/platform_shared_memory_region.h"
8 #include "base/numerics/safe_conversions.h"
9 #include "build/build_config.h"
10 
11 #if defined(OS_MACOSX) && !defined(OS_IOS)
12 #include <mach/mach.h>
13 #include "base/mac/mach_logging.h"
14 #endif
15 
16 namespace mojo {
17 
18 namespace {
19 
PlatformHandleValueFromPlatformFile(base::PlatformFile file)20 uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) {
21 #if defined(OS_WIN)
22   return reinterpret_cast<uint64_t>(file);
23 #else
24   return static_cast<uint64_t>(file);
25 #endif
26 }
27 
PlatformFileFromPlatformHandleValue(uint64_t value)28 base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) {
29 #if defined(OS_WIN)
30   return reinterpret_cast<base::PlatformFile>(value);
31 #else
32   return static_cast<base::PlatformFile>(value);
33 #endif
34 }
35 
WrapPlatformSharedMemoryRegion(base::subtle::PlatformSharedMemoryRegion region)36 ScopedSharedBufferHandle WrapPlatformSharedMemoryRegion(
37     base::subtle::PlatformSharedMemoryRegion region) {
38   if (!region.IsValid())
39     return ScopedSharedBufferHandle();
40 
41   MojoPlatformSharedMemoryRegionAccessMode access_mode;
42   switch (region.GetMode()) {
43     case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
44       access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
45       break;
46     case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
47       access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
48       break;
49     case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
50       access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
51       break;
52     default:
53       NOTREACHED();
54       return ScopedSharedBufferHandle();
55   }
56 
57   base::subtle::PlatformSharedMemoryRegion::ScopedPlatformHandle handle =
58       region.PassPlatformHandle();
59   MojoPlatformHandle platform_handles[2];
60   uint32_t num_platform_handles = 1;
61   platform_handles[0].struct_size = sizeof(platform_handles[0]);
62 #if defined(OS_WIN)
63   platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE;
64   platform_handles[0].value = reinterpret_cast<uint64_t>(handle.Take());
65 #elif defined(OS_FUCHSIA)
66   platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE;
67   platform_handles[0].value = static_cast<uint64_t>(handle.release());
68 #elif defined(OS_MACOSX) && !defined(OS_IOS)
69   platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
70   platform_handles[0].value = static_cast<uint64_t>(handle.release());
71 #elif defined(OS_ANDROID)
72   platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
73   platform_handles[0].value = static_cast<uint64_t>(handle.release());
74 #else
75   platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
76   platform_handles[0].value = static_cast<uint64_t>(handle.fd.release());
77 
78   if (region.GetMode() ==
79       base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
80     num_platform_handles = 2;
81     platform_handles[1].struct_size = sizeof(platform_handles[1]);
82     platform_handles[1].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR;
83     platform_handles[1].value =
84         static_cast<uint64_t>(handle.readonly_fd.release());
85   }
86 #endif
87   const auto& guid = region.GetGUID();
88   MojoSharedBufferGuid mojo_guid = {guid.GetHighForSerialization(),
89                                     guid.GetLowForSerialization()};
90   MojoHandle mojo_handle;
91   MojoResult result = MojoWrapPlatformSharedMemoryRegion(
92       platform_handles, num_platform_handles, region.GetSize(), &mojo_guid,
93       access_mode, nullptr, &mojo_handle);
94   if (result != MOJO_RESULT_OK)
95     return ScopedSharedBufferHandle();
96   return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
97 }
98 
UnwrapPlatformSharedMemoryRegion(ScopedSharedBufferHandle mojo_handle)99 base::subtle::PlatformSharedMemoryRegion UnwrapPlatformSharedMemoryRegion(
100     ScopedSharedBufferHandle mojo_handle) {
101   if (!mojo_handle.is_valid())
102     return base::subtle::PlatformSharedMemoryRegion();
103 
104   MojoPlatformHandle platform_handles[2];
105   platform_handles[0].struct_size = sizeof(platform_handles[0]);
106   platform_handles[1].struct_size = sizeof(platform_handles[1]);
107   uint32_t num_platform_handles = 2;
108   uint64_t size;
109   MojoSharedBufferGuid mojo_guid;
110   MojoPlatformSharedMemoryRegionAccessMode access_mode;
111   MojoResult result = MojoUnwrapPlatformSharedMemoryRegion(
112       mojo_handle.release().value(), nullptr, platform_handles,
113       &num_platform_handles, &size, &mojo_guid, &access_mode);
114   if (result != MOJO_RESULT_OK)
115     return base::subtle::PlatformSharedMemoryRegion();
116 
117   base::subtle::PlatformSharedMemoryRegion::ScopedPlatformHandle region_handle;
118 #if defined(OS_WIN)
119   if (num_platform_handles != 1)
120     return base::subtle::PlatformSharedMemoryRegion();
121   if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE)
122     return base::subtle::PlatformSharedMemoryRegion();
123   region_handle.Set(reinterpret_cast<HANDLE>(platform_handles[0].value));
124 #elif defined(OS_FUCHSIA)
125   if (num_platform_handles != 1)
126     return base::subtle::PlatformSharedMemoryRegion();
127   if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE)
128     return base::subtle::PlatformSharedMemoryRegion();
129   region_handle.reset(static_cast<zx_handle_t>(platform_handles[0].value));
130 #elif defined(OS_MACOSX) && !defined(OS_IOS)
131   if (num_platform_handles != 1)
132     return base::subtle::PlatformSharedMemoryRegion();
133   if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT)
134     return base::subtle::PlatformSharedMemoryRegion();
135   region_handle.reset(static_cast<mach_port_t>(platform_handles[0].value));
136 #elif defined(OS_ANDROID)
137   if (num_platform_handles != 1)
138     return base::subtle::PlatformSharedMemoryRegion();
139   if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
140     return base::subtle::PlatformSharedMemoryRegion();
141   region_handle.reset(static_cast<int>(platform_handles[0].value));
142 #else
143   if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
144     if (num_platform_handles != 2)
145       return base::subtle::PlatformSharedMemoryRegion();
146   } else if (num_platform_handles != 1) {
147     return base::subtle::PlatformSharedMemoryRegion();
148   }
149   if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
150     return base::subtle::PlatformSharedMemoryRegion();
151   region_handle.fd.reset(static_cast<int>(platform_handles[0].value));
152   if (num_platform_handles == 2) {
153     if (platform_handles[1].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR)
154       return base::subtle::PlatformSharedMemoryRegion();
155     region_handle.readonly_fd.reset(
156         static_cast<int>(platform_handles[1].value));
157   }
158 #endif
159 
160   base::subtle::PlatformSharedMemoryRegion::Mode mode;
161   switch (access_mode) {
162     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
163       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
164       break;
165     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
166       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
167       break;
168     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
169       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
170       break;
171     default:
172       return base::subtle::PlatformSharedMemoryRegion();
173   }
174 
175   return base::subtle::PlatformSharedMemoryRegion::Take(
176       std::move(region_handle), mode, size,
177       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low));
178 }
179 
180 }  // namespace
181 
WrapPlatformHandle(PlatformHandle handle)182 ScopedHandle WrapPlatformHandle(PlatformHandle handle) {
183   MojoPlatformHandle platform_handle;
184   PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handle);
185 
186   MojoHandle wrapped_handle;
187   MojoResult result =
188       MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle);
189   if (result != MOJO_RESULT_OK)
190     return ScopedHandle();
191   return ScopedHandle(Handle(wrapped_handle));
192 }
193 
UnwrapPlatformHandle(ScopedHandle handle)194 PlatformHandle UnwrapPlatformHandle(ScopedHandle handle) {
195   MojoPlatformHandle platform_handle;
196   platform_handle.struct_size = sizeof(platform_handle);
197   MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(),
198                                                nullptr, &platform_handle);
199   if (result != MOJO_RESULT_OK)
200     return PlatformHandle();
201   return PlatformHandle::FromMojoPlatformHandle(&platform_handle);
202 }
203 
204 // Wraps a PlatformFile as a Mojo handle. Takes ownership of the file object.
WrapPlatformFile(base::PlatformFile platform_file)205 ScopedHandle WrapPlatformFile(base::PlatformFile platform_file) {
206   MojoPlatformHandle platform_handle;
207   platform_handle.struct_size = sizeof(MojoPlatformHandle);
208   platform_handle.type = kPlatformFileHandleType;
209   platform_handle.value = PlatformHandleValueFromPlatformFile(platform_file);
210 
211   MojoHandle mojo_handle;
212   MojoResult result =
213       MojoWrapPlatformHandle(&platform_handle, nullptr, &mojo_handle);
214   CHECK_EQ(result, MOJO_RESULT_OK);
215 
216   return ScopedHandle(Handle(mojo_handle));
217 }
218 
UnwrapPlatformFile(ScopedHandle handle,base::PlatformFile * file)219 MojoResult UnwrapPlatformFile(ScopedHandle handle, base::PlatformFile* file) {
220   MojoPlatformHandle platform_handle;
221   platform_handle.struct_size = sizeof(MojoPlatformHandle);
222   MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(),
223                                                nullptr, &platform_handle);
224   if (result != MOJO_RESULT_OK)
225     return result;
226 
227   if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) {
228     *file = base::kInvalidPlatformFile;
229   } else {
230     CHECK_EQ(platform_handle.type, kPlatformFileHandleType);
231     *file = PlatformFileFromPlatformHandleValue(platform_handle.value);
232   }
233 
234   return MOJO_RESULT_OK;
235 }
236 
WrapSharedMemoryHandle(const base::SharedMemoryHandle & memory_handle,size_t size,UnwrappedSharedMemoryHandleProtection protection)237 ScopedSharedBufferHandle WrapSharedMemoryHandle(
238     const base::SharedMemoryHandle& memory_handle,
239     size_t size,
240     UnwrappedSharedMemoryHandleProtection protection) {
241   if (!memory_handle.IsValid())
242     return ScopedSharedBufferHandle();
243   MojoPlatformHandle platform_handle;
244   platform_handle.struct_size = sizeof(MojoPlatformHandle);
245   platform_handle.type = kPlatformSharedBufferHandleType;
246 #if defined(OS_MACOSX) && !defined(OS_IOS)
247   platform_handle.value =
248       static_cast<uint64_t>(memory_handle.GetMemoryObject());
249 #else
250   platform_handle.value =
251       PlatformHandleValueFromPlatformFile(memory_handle.GetHandle());
252 #endif
253 
254   MojoPlatformSharedMemoryRegionAccessMode access_mode =
255       MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
256   if (protection == UnwrappedSharedMemoryHandleProtection::kReadOnly) {
257     access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
258 
259 #if defined(OS_ANDROID)
260     // Many callers assume that base::SharedMemory::GetReadOnlyHandle() gives
261     // them a handle which is actually read-only. This assumption is invalid on
262     // Android. As a precursor to migrating all base::SharedMemory usage --
263     // including Mojo internals -- to the new base shared memory API, we ensure
264     // that regions are set to read-only if any of their handles are wrapped
265     // read-only. This relies on existing usages not attempting to map the
266     // region writable any time after this call.
267     if (!memory_handle.IsRegionReadOnly())
268       memory_handle.SetRegionReadOnly();
269 #endif
270   }
271 
272   MojoSharedBufferGuid guid;
273   guid.high = memory_handle.GetGUID().GetHighForSerialization();
274   guid.low = memory_handle.GetGUID().GetLowForSerialization();
275   MojoHandle mojo_handle;
276   MojoResult result = MojoWrapPlatformSharedMemoryRegion(
277       &platform_handle, 1, size, &guid, access_mode, nullptr, &mojo_handle);
278   CHECK_EQ(result, MOJO_RESULT_OK);
279 
280   return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle));
281 }
282 
UnwrapSharedMemoryHandle(ScopedSharedBufferHandle handle,base::SharedMemoryHandle * memory_handle,size_t * size,UnwrappedSharedMemoryHandleProtection * protection)283 MojoResult UnwrapSharedMemoryHandle(
284     ScopedSharedBufferHandle handle,
285     base::SharedMemoryHandle* memory_handle,
286     size_t* size,
287     UnwrappedSharedMemoryHandleProtection* protection) {
288   if (!handle.is_valid())
289     return MOJO_RESULT_INVALID_ARGUMENT;
290   MojoPlatformHandle platform_handles[2];
291   platform_handles[0].struct_size = sizeof(platform_handles[0]);
292   platform_handles[1].struct_size = sizeof(platform_handles[1]);
293 
294   uint32_t num_platform_handles = 2;
295   uint64_t num_bytes;
296   MojoSharedBufferGuid mojo_guid;
297   MojoPlatformSharedMemoryRegionAccessMode access_mode;
298   MojoResult result = MojoUnwrapPlatformSharedMemoryRegion(
299       handle.release().value(), nullptr, platform_handles,
300       &num_platform_handles, &num_bytes, &mojo_guid, &access_mode);
301   if (result != MOJO_RESULT_OK)
302     return result;
303 
304   if (size) {
305     DCHECK(base::IsValueInRangeForNumericType<size_t>(num_bytes));
306     *size = static_cast<size_t>(num_bytes);
307   }
308 
309   if (protection) {
310     *protection =
311         access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY
312             ? UnwrappedSharedMemoryHandleProtection::kReadOnly
313             : UnwrappedSharedMemoryHandleProtection::kReadWrite;
314   }
315 
316   base::UnguessableToken guid =
317       base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low);
318 #if defined(OS_MACOSX) && !defined(OS_IOS)
319   DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT);
320   DCHECK_EQ(num_platform_handles, 1u);
321   *memory_handle = base::SharedMemoryHandle(
322       static_cast<mach_port_t>(platform_handles[0].value), num_bytes, guid);
323 #elif defined(OS_FUCHSIA)
324   DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE);
325   DCHECK_EQ(num_platform_handles, 1u);
326   *memory_handle = base::SharedMemoryHandle(
327       static_cast<zx_handle_t>(platform_handles[0].value), num_bytes, guid);
328 #elif defined(OS_POSIX)
329   DCHECK_EQ(platform_handles[0].type,
330             MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR);
331   *memory_handle = base::SharedMemoryHandle(
332       base::FileDescriptor(static_cast<int>(platform_handles[0].value), false),
333       num_bytes, guid);
334 #if !defined(OS_ANDROID)
335   if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
336     DCHECK_EQ(num_platform_handles, 2u);
337     // When unwrapping as a base::SharedMemoryHandle, make sure to discard the
338     // extra file descriptor if the region is writable. base::SharedMemoryHandle
339     // effectively only supports read-only and unsafe usage modes when wrapping
340     // or unwrapping to and from Mojo handles.
341     base::ScopedFD discarded_readonly_fd(
342         static_cast<int>(platform_handles[1].value));
343   } else {
344     DCHECK_EQ(num_platform_handles, 1u);
345   }
346 #else   // !defined(OS_ANDROID)
347   DCHECK_EQ(num_platform_handles, 1u);
348 #endif  // !defined(OS_ANDROID)
349 #elif defined(OS_WIN)
350   DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE);
351   DCHECK_EQ(num_platform_handles, 1u);
352   *memory_handle = base::SharedMemoryHandle(
353       reinterpret_cast<HANDLE>(platform_handles[0].value), num_bytes, guid);
354 #endif
355 
356   return MOJO_RESULT_OK;
357 }
358 
WrapReadOnlySharedMemoryRegion(base::ReadOnlySharedMemoryRegion region)359 ScopedSharedBufferHandle WrapReadOnlySharedMemoryRegion(
360     base::ReadOnlySharedMemoryRegion region) {
361   return WrapPlatformSharedMemoryRegion(
362       base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
363           std::move(region)));
364 }
365 
WrapUnsafeSharedMemoryRegion(base::UnsafeSharedMemoryRegion region)366 ScopedSharedBufferHandle WrapUnsafeSharedMemoryRegion(
367     base::UnsafeSharedMemoryRegion region) {
368   return WrapPlatformSharedMemoryRegion(
369       base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
370           std::move(region)));
371 }
372 
WrapWritableSharedMemoryRegion(base::WritableSharedMemoryRegion region)373 ScopedSharedBufferHandle WrapWritableSharedMemoryRegion(
374     base::WritableSharedMemoryRegion region) {
375   return WrapPlatformSharedMemoryRegion(
376       base::WritableSharedMemoryRegion::TakeHandleForSerialization(
377           std::move(region)));
378 }
379 
UnwrapReadOnlySharedMemoryRegion(ScopedSharedBufferHandle handle)380 base::ReadOnlySharedMemoryRegion UnwrapReadOnlySharedMemoryRegion(
381     ScopedSharedBufferHandle handle) {
382   return base::ReadOnlySharedMemoryRegion::Deserialize(
383       UnwrapPlatformSharedMemoryRegion(std::move(handle)));
384 }
385 
UnwrapUnsafeSharedMemoryRegion(ScopedSharedBufferHandle handle)386 base::UnsafeSharedMemoryRegion UnwrapUnsafeSharedMemoryRegion(
387     ScopedSharedBufferHandle handle) {
388   return base::UnsafeSharedMemoryRegion::Deserialize(
389       UnwrapPlatformSharedMemoryRegion(std::move(handle)));
390 }
391 
UnwrapWritableSharedMemoryRegion(ScopedSharedBufferHandle handle)392 base::WritableSharedMemoryRegion UnwrapWritableSharedMemoryRegion(
393     ScopedSharedBufferHandle handle) {
394   return base::WritableSharedMemoryRegion::Deserialize(
395       UnwrapPlatformSharedMemoryRegion(std::move(handle)));
396 }
397 
398 #if defined(OS_MACOSX) && !defined(OS_IOS)
WrapMachPort(mach_port_t port)399 ScopedHandle WrapMachPort(mach_port_t port) {
400   kern_return_t kr =
401       mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1);
402   MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
403       << "MachPortAttachmentMac mach_port_mod_refs";
404   if (kr != KERN_SUCCESS)
405     return ScopedHandle();
406 
407   MojoPlatformHandle platform_handle;
408   platform_handle.struct_size = sizeof(MojoPlatformHandle);
409   platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT;
410   platform_handle.value = static_cast<uint64_t>(port);
411 
412   MojoHandle mojo_handle;
413   MojoResult result =
414       MojoWrapPlatformHandle(&platform_handle, nullptr, &mojo_handle);
415   CHECK_EQ(result, MOJO_RESULT_OK);
416 
417   return ScopedHandle(Handle(mojo_handle));
418 }
419 
UnwrapMachPort(ScopedHandle handle,mach_port_t * port)420 MojoResult UnwrapMachPort(ScopedHandle handle, mach_port_t* port) {
421   MojoPlatformHandle platform_handle;
422   platform_handle.struct_size = sizeof(MojoPlatformHandle);
423   MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(),
424                                                nullptr, &platform_handle);
425   if (result != MOJO_RESULT_OK)
426     return result;
427 
428   CHECK(platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT ||
429         platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID);
430   *port = static_cast<mach_port_t>(platform_handle.value);
431   return MOJO_RESULT_OK;
432 }
433 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
434 
435 }  // namespace mojo
436