Home | History | Annotate | Download | only in system
      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 
     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 
     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 
     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 
     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 
    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 
    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.
    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 
    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 
    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 
    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 
    359 ScopedSharedBufferHandle WrapReadOnlySharedMemoryRegion(
    360     base::ReadOnlySharedMemoryRegion region) {
    361   return WrapPlatformSharedMemoryRegion(
    362       base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
    363           std::move(region)));
    364 }
    365 
    366 ScopedSharedBufferHandle WrapUnsafeSharedMemoryRegion(
    367     base::UnsafeSharedMemoryRegion region) {
    368   return WrapPlatformSharedMemoryRegion(
    369       base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
    370           std::move(region)));
    371 }
    372 
    373 ScopedSharedBufferHandle WrapWritableSharedMemoryRegion(
    374     base::WritableSharedMemoryRegion region) {
    375   return WrapPlatformSharedMemoryRegion(
    376       base::WritableSharedMemoryRegion::TakeHandleForSerialization(
    377           std::move(region)));
    378 }
    379 
    380 base::ReadOnlySharedMemoryRegion UnwrapReadOnlySharedMemoryRegion(
    381     ScopedSharedBufferHandle handle) {
    382   return base::ReadOnlySharedMemoryRegion::Deserialize(
    383       UnwrapPlatformSharedMemoryRegion(std::move(handle)));
    384 }
    385 
    386 base::UnsafeSharedMemoryRegion UnwrapUnsafeSharedMemoryRegion(
    387     ScopedSharedBufferHandle handle) {
    388   return base::UnsafeSharedMemoryRegion::Deserialize(
    389       UnwrapPlatformSharedMemoryRegion(std::move(handle)));
    390 }
    391 
    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)
    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 
    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