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