• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/memory/platform_shared_memory_region.h"
6 
7 #include "base/memory/shared_memory_mapping.h"
8 #include "base/process/process_metrics.h"
9 #include "base/sys_info.h"
10 #include "base/test/gtest_util.h"
11 #include "base/test/test_shared_memory_util.h"
12 #include "build/build_config.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 
15 #if defined(OS_MACOSX) && !defined(OS_IOS)
16 #include <mach/mach_vm.h>
17 #endif
18 
19 namespace base {
20 namespace subtle {
21 
22 const size_t kRegionSize = 1024;
23 
24 class PlatformSharedMemoryRegionTest : public ::testing::Test {};
25 
26 // Tests that a default constructed region is invalid and produces invalid
27 // mappings.
TEST_F(PlatformSharedMemoryRegionTest,DefaultConstructedRegionIsInvalid)28 TEST_F(PlatformSharedMemoryRegionTest, DefaultConstructedRegionIsInvalid) {
29   PlatformSharedMemoryRegion region;
30   EXPECT_FALSE(region.IsValid());
31   WritableSharedMemoryMapping mapping = MapForTesting(&region);
32   EXPECT_FALSE(mapping.IsValid());
33   PlatformSharedMemoryRegion duplicate = region.Duplicate();
34   EXPECT_FALSE(duplicate.IsValid());
35   EXPECT_FALSE(region.ConvertToReadOnly());
36 }
37 
38 // Tests that creating a region of 0 size returns an invalid region.
TEST_F(PlatformSharedMemoryRegionTest,CreateRegionOfZeroSizeIsInvalid)39 TEST_F(PlatformSharedMemoryRegionTest, CreateRegionOfZeroSizeIsInvalid) {
40   PlatformSharedMemoryRegion region =
41       PlatformSharedMemoryRegion::CreateWritable(0);
42   EXPECT_FALSE(region.IsValid());
43 
44   PlatformSharedMemoryRegion region2 =
45       PlatformSharedMemoryRegion::CreateUnsafe(0);
46   EXPECT_FALSE(region2.IsValid());
47 }
48 
49 // Tests that creating a region of size bigger than the integer max value
50 // returns an invalid region.
TEST_F(PlatformSharedMemoryRegionTest,CreateTooLargeRegionIsInvalid)51 TEST_F(PlatformSharedMemoryRegionTest, CreateTooLargeRegionIsInvalid) {
52   size_t too_large_region_size =
53       static_cast<size_t>(std::numeric_limits<int>::max()) + 1;
54   PlatformSharedMemoryRegion region =
55       PlatformSharedMemoryRegion::CreateWritable(too_large_region_size);
56   EXPECT_FALSE(region.IsValid());
57 
58   PlatformSharedMemoryRegion region2 =
59       PlatformSharedMemoryRegion::CreateUnsafe(too_large_region_size);
60   EXPECT_FALSE(region2.IsValid());
61 }
62 
63 // Tests that regions consistently report their size as the size requested at
64 // creation time even if their allocation size is larger due to platform
65 // constraints.
TEST_F(PlatformSharedMemoryRegionTest,ReportedSizeIsRequestedSize)66 TEST_F(PlatformSharedMemoryRegionTest, ReportedSizeIsRequestedSize) {
67   constexpr size_t kTestSizes[] = {1, 2, 3, 64, 4096, 1024 * 1024};
68   for (size_t size : kTestSizes) {
69     PlatformSharedMemoryRegion region =
70         PlatformSharedMemoryRegion::CreateWritable(size);
71     EXPECT_EQ(region.GetSize(), size);
72 
73     region.ConvertToReadOnly();
74     EXPECT_EQ(region.GetSize(), size);
75   }
76 }
77 
78 // Tests that a writable region can be converted to read-only.
TEST_F(PlatformSharedMemoryRegionTest,ConvertWritableToReadOnly)79 TEST_F(PlatformSharedMemoryRegionTest, ConvertWritableToReadOnly) {
80   PlatformSharedMemoryRegion region =
81       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
82   ASSERT_TRUE(region.IsValid());
83   EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kWritable);
84   ASSERT_TRUE(region.ConvertToReadOnly());
85   EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly);
86 }
87 
88 // Tests that a writable region can be converted to unsafe.
TEST_F(PlatformSharedMemoryRegionTest,ConvertWritableToUnsafe)89 TEST_F(PlatformSharedMemoryRegionTest, ConvertWritableToUnsafe) {
90   PlatformSharedMemoryRegion region =
91       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
92   ASSERT_TRUE(region.IsValid());
93   EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kWritable);
94   ASSERT_TRUE(region.ConvertToUnsafe());
95   EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kUnsafe);
96 }
97 
98 // Tests that the platform-specific handle converted to read-only cannot be used
99 // to perform a writable mapping with low-level system APIs like mmap().
TEST_F(PlatformSharedMemoryRegionTest,ReadOnlyHandleIsNotWritable)100 TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyHandleIsNotWritable) {
101   PlatformSharedMemoryRegion region =
102       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
103   ASSERT_TRUE(region.IsValid());
104   EXPECT_TRUE(region.ConvertToReadOnly());
105   EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly);
106   EXPECT_TRUE(
107       CheckReadOnlyPlatformSharedMemoryRegionForTesting(std::move(region)));
108 }
109 
110 // Tests that the PassPlatformHandle() call invalidates the region.
TEST_F(PlatformSharedMemoryRegionTest,InvalidAfterPass)111 TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterPass) {
112   PlatformSharedMemoryRegion region =
113       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
114   ASSERT_TRUE(region.IsValid());
115   ignore_result(region.PassPlatformHandle());
116   EXPECT_FALSE(region.IsValid());
117 }
118 
119 // Tests that the region is invalid after move.
TEST_F(PlatformSharedMemoryRegionTest,InvalidAfterMove)120 TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterMove) {
121   PlatformSharedMemoryRegion region =
122       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
123   ASSERT_TRUE(region.IsValid());
124   PlatformSharedMemoryRegion moved_region = std::move(region);
125   EXPECT_FALSE(region.IsValid());
126   EXPECT_TRUE(moved_region.IsValid());
127 }
128 
129 // Tests that calling Take() with the size parameter equal to zero returns an
130 // invalid region.
TEST_F(PlatformSharedMemoryRegionTest,TakeRegionOfZeroSizeIsInvalid)131 TEST_F(PlatformSharedMemoryRegionTest, TakeRegionOfZeroSizeIsInvalid) {
132   PlatformSharedMemoryRegion region =
133       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
134   ASSERT_TRUE(region.IsValid());
135   PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
136       region.PassPlatformHandle(), region.GetMode(), 0, region.GetGUID());
137   EXPECT_FALSE(region2.IsValid());
138 }
139 
140 // Tests that calling Take() with the size parameter bigger than the integer max
141 // value returns an invalid region.
TEST_F(PlatformSharedMemoryRegionTest,TakeTooLargeRegionIsInvalid)142 TEST_F(PlatformSharedMemoryRegionTest, TakeTooLargeRegionIsInvalid) {
143   PlatformSharedMemoryRegion region =
144       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
145   ASSERT_TRUE(region.IsValid());
146   PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
147       region.PassPlatformHandle(), region.GetMode(),
148       static_cast<size_t>(std::numeric_limits<int>::max()) + 1,
149       region.GetGUID());
150   EXPECT_FALSE(region2.IsValid());
151 }
152 
153 // Tests that mapping bytes out of the region limits fails.
TEST_F(PlatformSharedMemoryRegionTest,MapAtOutOfTheRegionLimitsTest)154 TEST_F(PlatformSharedMemoryRegionTest, MapAtOutOfTheRegionLimitsTest) {
155   PlatformSharedMemoryRegion region =
156       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
157   ASSERT_TRUE(region.IsValid());
158   WritableSharedMemoryMapping mapping =
159       MapAtForTesting(&region, 0, region.GetSize() + 1);
160   EXPECT_FALSE(mapping.IsValid());
161 }
162 
163 // Tests that mapping with a size and offset causing overflow fails.
TEST_F(PlatformSharedMemoryRegionTest,MapAtWithOverflowTest)164 TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) {
165   PlatformSharedMemoryRegion region =
166       PlatformSharedMemoryRegion::CreateWritable(
167           SysInfo::VMAllocationGranularity() * 2);
168   ASSERT_TRUE(region.IsValid());
169   size_t size = std::numeric_limits<size_t>::max();
170   size_t offset = SysInfo::VMAllocationGranularity();
171   // |size| + |offset| should be below the region size due to overflow but
172   // mapping a region with these parameters should be invalid.
173   EXPECT_LT(size + offset, region.GetSize());
174   WritableSharedMemoryMapping mapping = MapAtForTesting(&region, offset, size);
175   EXPECT_FALSE(mapping.IsValid());
176 }
177 
178 #if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
179 // Tests that the second handle is closed after a conversion to read-only on
180 // POSIX.
TEST_F(PlatformSharedMemoryRegionTest,ConvertToReadOnlyInvalidatesSecondHandle)181 TEST_F(PlatformSharedMemoryRegionTest,
182        ConvertToReadOnlyInvalidatesSecondHandle) {
183   PlatformSharedMemoryRegion region =
184       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
185   ASSERT_TRUE(region.IsValid());
186   ASSERT_TRUE(region.ConvertToReadOnly());
187   FDPair fds = region.GetPlatformHandle();
188   EXPECT_LT(fds.readonly_fd, 0);
189 }
190 
191 // Tests that the second handle is closed after a conversion to unsafe on
192 // POSIX.
TEST_F(PlatformSharedMemoryRegionTest,ConvertToUnsafeInvalidatesSecondHandle)193 TEST_F(PlatformSharedMemoryRegionTest, ConvertToUnsafeInvalidatesSecondHandle) {
194   PlatformSharedMemoryRegion region =
195       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
196   ASSERT_TRUE(region.IsValid());
197   ASSERT_TRUE(region.ConvertToUnsafe());
198   FDPair fds = region.GetPlatformHandle();
199   EXPECT_LT(fds.readonly_fd, 0);
200 }
201 #endif
202 
203 #if defined(OS_MACOSX) && !defined(OS_IOS)
204 // Tests that protection bits are set correctly for read-only region on MacOS.
TEST_F(PlatformSharedMemoryRegionTest,MapCurrentAndMaxProtectionSetCorrectly)205 TEST_F(PlatformSharedMemoryRegionTest, MapCurrentAndMaxProtectionSetCorrectly) {
206   PlatformSharedMemoryRegion region =
207       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
208   ASSERT_TRUE(region.IsValid());
209   ASSERT_TRUE(region.ConvertToReadOnly());
210   WritableSharedMemoryMapping ro_mapping = MapForTesting(&region);
211   ASSERT_TRUE(ro_mapping.IsValid());
212 
213   vm_region_basic_info_64 basic_info;
214   mach_vm_size_t dummy_size = 0;
215   void* temp_addr = ro_mapping.memory();
216   MachVMRegionResult result = GetBasicInfo(
217       mach_task_self(), &dummy_size,
218       reinterpret_cast<mach_vm_address_t*>(&temp_addr), &basic_info);
219   EXPECT_EQ(result, MachVMRegionResult::Success);
220   EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ);
221   EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ);
222 }
223 #endif
224 
225 // Tests that platform handle permissions are checked correctly.
TEST_F(PlatformSharedMemoryRegionTest,CheckPlatformHandlePermissionsCorrespondToMode)226 TEST_F(PlatformSharedMemoryRegionTest,
227        CheckPlatformHandlePermissionsCorrespondToMode) {
228   using Mode = PlatformSharedMemoryRegion::Mode;
229   auto check = [](const PlatformSharedMemoryRegion& region,
230                   PlatformSharedMemoryRegion::Mode mode) {
231     return PlatformSharedMemoryRegion::
232         CheckPlatformHandlePermissionsCorrespondToMode(
233             region.GetPlatformHandle(), mode, region.GetSize());
234   };
235 
236   // Check kWritable region.
237   PlatformSharedMemoryRegion region =
238       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
239   ASSERT_TRUE(region.IsValid());
240   EXPECT_TRUE(check(region, Mode::kWritable));
241   EXPECT_FALSE(check(region, Mode::kReadOnly));
242 
243   // Check kReadOnly region.
244   ASSERT_TRUE(region.ConvertToReadOnly());
245   EXPECT_TRUE(check(region, Mode::kReadOnly));
246   EXPECT_FALSE(check(region, Mode::kWritable));
247   EXPECT_FALSE(check(region, Mode::kUnsafe));
248 
249   // Check kUnsafe region.
250   PlatformSharedMemoryRegion region2 =
251       PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
252   ASSERT_TRUE(region2.IsValid());
253   EXPECT_TRUE(check(region2, Mode::kUnsafe));
254   EXPECT_FALSE(check(region2, Mode::kReadOnly));
255 }
256 
257 // Tests that it's impossible to create read-only platform shared memory region.
TEST_F(PlatformSharedMemoryRegionTest,CreateReadOnlyRegionDeathTest)258 TEST_F(PlatformSharedMemoryRegionTest, CreateReadOnlyRegionDeathTest) {
259 #ifdef OFFICIAL_BUILD
260   // The official build does not print the reason a CHECK failed.
261   const char kErrorRegex[] = "";
262 #else
263   const char kErrorRegex[] =
264       "Creating a region in read-only mode will lead to this region being "
265       "non-modifiable";
266 #endif
267   EXPECT_DEATH_IF_SUPPORTED(
268       PlatformSharedMemoryRegion::Create(
269           PlatformSharedMemoryRegion::Mode::kReadOnly, kRegionSize),
270       kErrorRegex);
271 }
272 
273 // Tests that it's prohibited to duplicate a writable region.
TEST_F(PlatformSharedMemoryRegionTest,DuplicateWritableRegionDeathTest)274 TEST_F(PlatformSharedMemoryRegionTest, DuplicateWritableRegionDeathTest) {
275 #ifdef OFFICIAL_BUILD
276   const char kErrorRegex[] = "";
277 #else
278   const char kErrorRegex[] =
279       "Duplicating a writable shared memory region is prohibited";
280 #endif
281   PlatformSharedMemoryRegion region =
282       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
283   ASSERT_TRUE(region.IsValid());
284   EXPECT_DEATH_IF_SUPPORTED(region.Duplicate(), kErrorRegex);
285 }
286 
287 // Tests that it's prohibited to convert an unsafe region to read-only.
TEST_F(PlatformSharedMemoryRegionTest,UnsafeRegionConvertToReadOnlyDeathTest)288 TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToReadOnlyDeathTest) {
289 #ifdef OFFICIAL_BUILD
290   const char kErrorRegex[] = "";
291 #else
292   const char kErrorRegex[] =
293       "Only writable shared memory region can be converted to read-only";
294 #endif
295   PlatformSharedMemoryRegion region =
296       PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
297   ASSERT_TRUE(region.IsValid());
298   EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
299 }
300 
301 // Tests that it's prohibited to convert a read-only region to read-only.
TEST_F(PlatformSharedMemoryRegionTest,ReadOnlyRegionConvertToReadOnlyDeathTest)302 TEST_F(PlatformSharedMemoryRegionTest,
303        ReadOnlyRegionConvertToReadOnlyDeathTest) {
304 #ifdef OFFICIAL_BUILD
305   const char kErrorRegex[] = "";
306 #else
307   const char kErrorRegex[] =
308       "Only writable shared memory region can be converted to read-only";
309 #endif
310   PlatformSharedMemoryRegion region =
311       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
312   ASSERT_TRUE(region.IsValid());
313   EXPECT_TRUE(region.ConvertToReadOnly());
314   EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
315 }
316 
317 // Tests that it's prohibited to convert a read-only region to unsafe.
TEST_F(PlatformSharedMemoryRegionTest,ReadOnlyRegionConvertToUnsafeDeathTest)318 TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyRegionConvertToUnsafeDeathTest) {
319 #ifdef OFFICIAL_BUILD
320   const char kErrorRegex[] = "";
321 #else
322   const char kErrorRegex[] =
323       "Only writable shared memory region can be converted to unsafe";
324 #endif
325   PlatformSharedMemoryRegion region =
326       PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
327   ASSERT_TRUE(region.IsValid());
328   ASSERT_TRUE(region.ConvertToReadOnly());
329   EXPECT_DEATH_IF_SUPPORTED(region.ConvertToUnsafe(), kErrorRegex);
330 }
331 
332 // Tests that it's prohibited to convert an unsafe region to unsafe.
TEST_F(PlatformSharedMemoryRegionTest,UnsafeRegionConvertToUnsafeDeathTest)333 TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToUnsafeDeathTest) {
334 #ifdef OFFICIAL_BUILD
335   const char kErrorRegex[] = "";
336 #else
337   const char kErrorRegex[] =
338       "Only writable shared memory region can be converted to unsafe";
339 #endif
340   PlatformSharedMemoryRegion region =
341       PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
342   ASSERT_TRUE(region.IsValid());
343   EXPECT_DEATH_IF_SUPPORTED(region.ConvertToUnsafe(), kErrorRegex);
344 }
345 
346 }  // namespace subtle
347 }  // namespace base
348