1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/test/test_shared_memory_util.h"
#include <gtest/gtest.h>
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "build/build_config.h"
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_NACL)
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#endif
#if BUILDFLAG(IS_FUCHSIA)
#include <lib/zx/vmar.h>
#include <zircon/rights.h>
#endif
#if BUILDFLAG(IS_APPLE)
#include <mach/vm_map.h>
#endif
#if BUILDFLAG(IS_WIN)
#include <aclapi.h>
#endif
namespace base {
#if !BUILDFLAG(IS_NACL)
static const size_t kDataSize = 1024;
// Common routine used with Posix file descriptors. Check that shared memory
// file descriptor |fd| does not allow writable mappings. Return true on
// success, false otherwise.
#if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
static bool CheckReadOnlySharedMemoryFdPosix(int fd) {
// Note that the error on Android is EPERM, unlike other platforms where
// it will be EACCES.
#if BUILDFLAG(IS_ANDROID)
const int kExpectedErrno = EPERM;
#else
const int kExpectedErrno = EACCES;
#endif
errno = 0;
void* address =
mmap(nullptr, kDataSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
const bool success = (address != nullptr) && (address != MAP_FAILED);
if (success) {
LOG(ERROR) << "mmap() should have failed!";
munmap(address, kDataSize); // Cleanup.
return false;
}
if (errno != kExpectedErrno) {
PLOG(ERROR) << "Expected mmap() to return " << kExpectedErrno
<< " but returned"; // PLOG will append the actual errno value.
return false;
}
return true;
}
#endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_APPLE)
#if BUILDFLAG(IS_FUCHSIA)
// Fuchsia specific implementation.
bool CheckReadOnlySharedMemoryFuchsiaHandle(zx::unowned_vmo handle) {
const uint32_t flags = ZX_VM_PERM_READ | ZX_VM_PERM_WRITE;
uintptr_t addr;
const zx_status_t status =
zx::vmar::root_self()->map(flags, 0, *handle, 0U, kDataSize, &addr);
if (status == ZX_OK) {
LOG(ERROR) << "zx_vmar_map() should have failed!";
zx::vmar::root_self()->unmap(addr, kDataSize);
return false;
}
if (status != ZX_ERR_ACCESS_DENIED) {
LOG(ERROR) << "Expected zx_vmar_map() to return " << ZX_ERR_ACCESS_DENIED
<< " (ZX_ERR_ACCESS_DENIED) but returned " << status << "\n";
return false;
}
return true;
}
#elif BUILDFLAG(IS_APPLE)
bool CheckReadOnlySharedMemoryMachPort(mach_port_t memory_object) {
vm_address_t memory;
const kern_return_t kr =
vm_map(mach_task_self(), &memory, kDataSize, 0, VM_FLAGS_ANYWHERE,
memory_object, 0, FALSE, VM_PROT_READ | VM_PROT_WRITE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_IS_MASK, VM_INHERIT_NONE);
if (kr == KERN_SUCCESS) {
LOG(ERROR) << "vm_map() should have failed!";
vm_deallocate(mach_task_self(), memory, kDataSize); // Cleanup.
return false;
}
return true;
}
#elif BUILDFLAG(IS_WIN)
bool CheckReadOnlySharedMemoryWindowsHandle(HANDLE handle) {
void* memory =
MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kDataSize);
if (memory != nullptr) {
LOG(ERROR) << "MapViewOfFile() should have failed!";
UnmapViewOfFile(memory);
return false;
}
return true;
}
#endif
bool CheckReadOnlyPlatformSharedMemoryRegionForTesting(
subtle::PlatformSharedMemoryRegion region) {
if (region.GetMode() != subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
LOG(ERROR) << "Expected region mode is "
<< static_cast<int>(
subtle::PlatformSharedMemoryRegion::Mode::kReadOnly)
<< " but actual is " << static_cast<int>(region.GetMode());
return false;
}
#if BUILDFLAG(IS_APPLE)
return CheckReadOnlySharedMemoryMachPort(region.GetPlatformHandle());
#elif BUILDFLAG(IS_FUCHSIA)
return CheckReadOnlySharedMemoryFuchsiaHandle(region.GetPlatformHandle());
#elif BUILDFLAG(IS_WIN)
return CheckReadOnlySharedMemoryWindowsHandle(region.GetPlatformHandle());
#elif BUILDFLAG(IS_ANDROID)
return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle());
#else
return CheckReadOnlySharedMemoryFdPosix(region.GetPlatformHandle().fd);
#endif
}
#endif // !BUILDFLAG(IS_NACL)
WritableSharedMemoryMapping MapForTesting(
subtle::PlatformSharedMemoryRegion* region) {
return MapAtForTesting(region, 0, region->GetSize());
}
WritableSharedMemoryMapping MapAtForTesting(
subtle::PlatformSharedMemoryRegion* region,
uint64_t offset,
size_t size) {
SharedMemoryMapper* mapper = SharedMemoryMapper::GetDefaultInstance();
auto result = region->MapAt(offset, size, mapper);
if (!result.has_value()) {
return {};
}
return WritableSharedMemoryMapping(result.value(), size, region->GetGUID(),
mapper);
}
template <>
std::pair<ReadOnlySharedMemoryRegion, WritableSharedMemoryMapping>
CreateMappedRegion(size_t size) {
MappedReadOnlyRegion mapped_region = ReadOnlySharedMemoryRegion::Create(size);
return {std::move(mapped_region.region), std::move(mapped_region.mapping)};
}
} // namespace base
|