Home | History | Annotate | Download | only in test
      1 // Copyright 2017 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 "base/test/test_shared_memory_util.h"
      6 
      7 #include <gtest/gtest.h>
      8 
      9 #include <stddef.h>
     10 #include <stdint.h>
     11 
     12 #include "base/logging.h"
     13 #include "build/build_config.h"
     14 
     15 #if defined(OS_POSIX) && !defined(OS_NACL)
     16 #include <errno.h>
     17 #include <string.h>
     18 #include <sys/mman.h>
     19 #include <unistd.h>
     20 #endif
     21 
     22 #if defined(OS_FUCHSIA)
     23 #include <zircon/process.h>
     24 #include <zircon/rights.h>
     25 #include <zircon/syscalls.h>
     26 #endif
     27 
     28 #if defined(OS_MACOSX) && !defined(OS_IOS)
     29 #include <mach/mach_vm.h>
     30 #endif
     31 
     32 #if defined(OS_WIN)
     33 #include <aclapi.h>
     34 #endif
     35 
     36 namespace base {
     37 
     38 #if !defined(OS_NACL)
     39 
     40 static const size_t kDataSize = 1024;
     41 
     42 // Common routine used with Posix file descriptors. Check that shared memory
     43 // file descriptor |fd| does not allow writable mappings. Return true on
     44 // success, false otherwise.
     45 #if defined(OS_POSIX)
     46 static bool CheckReadOnlySharedMemoryFdPosix(int fd) {
     47 // Note that the error on Android is EPERM, unlike other platforms where
     48 // it will be EACCES.
     49 #if defined(OS_ANDROID)
     50   const int kExpectedErrno = EPERM;
     51 #else
     52   const int kExpectedErrno = EACCES;
     53 #endif
     54   errno = 0;
     55   void* address =
     56       mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     57   const bool success = (address != nullptr) && (address != MAP_FAILED);
     58   if (success) {
     59     LOG(ERROR) << "mmap() should have failed!";
     60     munmap(address, kDataSize);  // Cleanup.
     61     return false;
     62   }
     63   if (errno != kExpectedErrno) {
     64     LOG(ERROR) << "Expected mmap() to return " << kExpectedErrno
     65                << " but returned " << errno << ": " << strerror(errno) << "\n";
     66     return false;
     67   }
     68   return true;
     69 }
     70 #endif  // OS_POSIX && !OS_FUCHSIA
     71 
     72 #if defined(OS_FUCHSIA)
     73 // Fuchsia specific implementation.
     74 bool CheckReadOnlySharedMemoryFuchsiaHandle(zx_handle_t handle) {
     75   const uint32_t flags = ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE;
     76   uintptr_t addr;
     77   const zx_handle_t root = zx_vmar_root_self();
     78   const zx_status_t status =
     79       zx_vmar_map(root, 0, handle, 0U, kDataSize, flags, &addr);
     80   if (status == ZX_OK) {
     81     LOG(ERROR) << "zx_vmar_map() should have failed!";
     82     zx_vmar_unmap(root, addr, kDataSize);
     83     return false;
     84   }
     85   if (status != ZX_ERR_ACCESS_DENIED) {
     86     LOG(ERROR) << "Expected zx_vmar_map() to return " << ZX_ERR_ACCESS_DENIED
     87                << " (ZX_ERR_ACCESS_DENIED) but returned " << status << "\n";
     88     return false;
     89   }
     90   return true;
     91 }
     92 
     93 #elif defined(OS_MACOSX) && !defined(OS_IOS)
     94 bool CheckReadOnlySharedMemoryMachPort(mach_port_t memory_object) {
     95   mach_vm_address_t memory;
     96   const kern_return_t kr = mach_vm_map(
     97       mach_task_self(), &memory, kDataSize, 0, VM_FLAGS_ANYWHERE, memory_object,
     98       0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
     99       VM_PROT_READ | VM_PROT_WRITE | VM_PROT_IS_MASK, VM_INHERIT_NONE);
    100   if (kr == KERN_SUCCESS) {
    101     LOG(ERROR) << "mach_vm_map() should have failed!";
    102     mach_vm_deallocate(mach_task_self(), memory, kDataSize);  // Cleanup.
    103     return false;
    104   }
    105   return true;
    106 }
    107 
    108 #elif defined(OS_WIN)
    109 bool CheckReadOnlySharedMemoryWindowsHandle(HANDLE handle) {
    110   void* memory =
    111       MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kDataSize);
    112   if (memory != nullptr) {
    113     LOG(ERROR) << "MapViewOfFile() should have failed!";
    114     UnmapViewOfFile(memory);
    115     return false;
    116   }
    117   return true;
    118 }
    119 #endif
    120 
    121 bool CheckReadOnlySharedMemoryHandleForTesting(SharedMemoryHandle handle) {
    122 #if defined(OS_MACOSX) && !defined(OS_IOS)
    123   // For OSX, the code has to deal with both POSIX and MACH handles.
    124   if (handle.type_ == SharedMemoryHandle::POSIX)
    125     return CheckReadOnlySharedMemoryFdPosix(handle.file_descriptor_.fd);
    126   else
    127     return CheckReadOnlySharedMemoryMachPort(handle.memory_object_);
    128 #elif defined(OS_FUCHSIA)
    129   return CheckReadOnlySharedMemoryFuchsiaHandle(handle.GetHandle());
    130 #elif defined(OS_WIN)
    131   return CheckReadOnlySharedMemoryWindowsHandle(handle.GetHandle());
    132 #else
    133   return CheckReadOnlySharedMemoryFdPosix(handle.GetHandle());
    134 #endif
    135 }
    136 
    137 bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
    138     subtle::PlatformSharedMemoryRegion region) {
    139   if (region.GetMode() != subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
    140     LOG(ERROR) << "Expected region mode is "
    141                << static_cast<int>(
    142                       subtle::PlatformSharedMemoryRegion::Mode::kReadOnly)
    143                << " but actual is " << static_cast<int>(region.GetMode());
    144     return false;
    145   }
    146 
    147 #if defined(OS_MACOSX) && !defined(OS_IOS)
    148   return CheckReadOnlySharedMemoryMachPort(region.GetPlatformHandle());
    149 #elif defined(OS_FUCHSIA)
    150   return CheckReadOnlySharedMemoryFuchsiaHandle(region.GetPlatformHandle());
    151 #elif defined(OS_WIN)
    152   return CheckReadOnlySharedMemoryWindowsHandle(region.GetPlatformHandle());
    153 #elif defined(OS_ANDROID)
    154   return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle());
    155 #else
    156   return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle().fd);
    157 #endif
    158 }
    159 
    160 #endif  // !OS_NACL
    161 
    162 WritableSharedMemoryMapping MapForTesting(
    163     subtle::PlatformSharedMemoryRegion* region) {
    164   return MapAtForTesting(region, 0, region->GetSize());
    165 }
    166 
    167 WritableSharedMemoryMapping MapAtForTesting(
    168     subtle::PlatformSharedMemoryRegion* region,
    169     off_t offset,
    170     size_t size) {
    171   void* memory = nullptr;
    172   size_t mapped_size = 0;
    173   if (!region->MapAt(offset, size, &memory, &mapped_size))
    174     return {};
    175 
    176   return WritableSharedMemoryMapping(memory, size, mapped_size,
    177                                      region->GetGUID());
    178 }
    179 
    180 template <>
    181 std::pair<ReadOnlySharedMemoryRegion, WritableSharedMemoryMapping>
    182 CreateMappedRegion(size_t size) {
    183   MappedReadOnlyRegion mapped_region = ReadOnlySharedMemoryRegion::Create(size);
    184   return {std::move(mapped_region.region), std::move(mapped_region.mapping)};
    185 }
    186 
    187 }  // namespace base
    188