platform_shared_memory_region_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  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. #include "base/memory/platform_shared_memory_region.h"
  5. #include <tuple>
  6. #include "base/check.h"
  7. #include "base/memory/shared_memory_mapping.h"
  8. #include "base/process/process_metrics.h"
  9. #include "base/ranges/algorithm.h"
  10. #include "base/system/sys_info.h"
  11. #include "base/test/gtest_util.h"
  12. #include "base/test/test_shared_memory_util.h"
  13. #include "build/build_config.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #if BUILDFLAG(IS_APPLE)
  16. #include <mach/vm_map.h>
  17. #include <sys/mman.h>
  18. #elif BUILDFLAG(IS_POSIX)
  19. #include <sys/mman.h>
  20. #include "base/debug/proc_maps_linux.h"
  21. #elif BUILDFLAG(IS_WIN)
  22. #include <windows.h>
  23. #include "base/logging.h"
  24. #elif BUILDFLAG(IS_FUCHSIA)
  25. #include <lib/zx/object.h>
  26. #include <lib/zx/process.h>
  27. #include "base/fuchsia/fuchsia_logging.h"
  28. #endif
  29. namespace base {
  30. namespace subtle {
  31. const size_t kRegionSize = 1024;
  32. class PlatformSharedMemoryRegionTest : public ::testing::Test {};
  33. // Tests that a default constructed region is invalid and produces invalid
  34. // mappings.
  35. TEST_F(PlatformSharedMemoryRegionTest, DefaultConstructedRegionIsInvalid) {
  36. PlatformSharedMemoryRegion region;
  37. EXPECT_FALSE(region.IsValid());
  38. WritableSharedMemoryMapping mapping = MapForTesting(&region);
  39. EXPECT_FALSE(mapping.IsValid());
  40. PlatformSharedMemoryRegion duplicate = region.Duplicate();
  41. EXPECT_FALSE(duplicate.IsValid());
  42. EXPECT_FALSE(region.ConvertToReadOnly());
  43. }
  44. // Tests that creating a region of 0 size returns an invalid region.
  45. TEST_F(PlatformSharedMemoryRegionTest, CreateRegionOfZeroSizeIsInvalid) {
  46. PlatformSharedMemoryRegion region =
  47. PlatformSharedMemoryRegion::CreateWritable(0);
  48. EXPECT_FALSE(region.IsValid());
  49. PlatformSharedMemoryRegion region2 =
  50. PlatformSharedMemoryRegion::CreateUnsafe(0);
  51. EXPECT_FALSE(region2.IsValid());
  52. }
  53. // Tests that creating a region of size bigger than the integer max value
  54. // returns an invalid region.
  55. TEST_F(PlatformSharedMemoryRegionTest, CreateTooLargeRegionIsInvalid) {
  56. size_t too_large_region_size =
  57. static_cast<size_t>(std::numeric_limits<int>::max()) + 1;
  58. PlatformSharedMemoryRegion region =
  59. PlatformSharedMemoryRegion::CreateWritable(too_large_region_size);
  60. EXPECT_FALSE(region.IsValid());
  61. PlatformSharedMemoryRegion region2 =
  62. PlatformSharedMemoryRegion::CreateUnsafe(too_large_region_size);
  63. EXPECT_FALSE(region2.IsValid());
  64. }
  65. // Tests that creating a region of maximum possible value returns an invalid
  66. // region.
  67. TEST_F(PlatformSharedMemoryRegionTest, CreateMaxSizeRegionIsInvalid) {
  68. size_t max_region_size = std::numeric_limits<size_t>::max();
  69. PlatformSharedMemoryRegion region =
  70. PlatformSharedMemoryRegion::CreateWritable(max_region_size);
  71. EXPECT_FALSE(region.IsValid());
  72. PlatformSharedMemoryRegion region2 =
  73. PlatformSharedMemoryRegion::CreateUnsafe(max_region_size);
  74. EXPECT_FALSE(region2.IsValid());
  75. }
  76. // Tests that regions consistently report their size as the size requested at
  77. // creation time even if their allocation size is larger due to platform
  78. // constraints.
  79. TEST_F(PlatformSharedMemoryRegionTest, ReportedSizeIsRequestedSize) {
  80. constexpr size_t kTestSizes[] = {1, 2, 3, 64, 4096, 1024 * 1024};
  81. for (size_t size : kTestSizes) {
  82. PlatformSharedMemoryRegion region =
  83. PlatformSharedMemoryRegion::CreateWritable(size);
  84. EXPECT_EQ(region.GetSize(), size);
  85. region.ConvertToReadOnly();
  86. EXPECT_EQ(region.GetSize(), size);
  87. }
  88. }
  89. // Tests that a writable region can be converted to read-only.
  90. TEST_F(PlatformSharedMemoryRegionTest, ConvertWritableToReadOnly) {
  91. PlatformSharedMemoryRegion region =
  92. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  93. ASSERT_TRUE(region.IsValid());
  94. EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kWritable);
  95. ASSERT_TRUE(region.ConvertToReadOnly());
  96. EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly);
  97. }
  98. // Tests that a writable region can be converted to unsafe.
  99. TEST_F(PlatformSharedMemoryRegionTest, ConvertWritableToUnsafe) {
  100. PlatformSharedMemoryRegion region =
  101. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  102. ASSERT_TRUE(region.IsValid());
  103. EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kWritable);
  104. ASSERT_TRUE(region.ConvertToUnsafe());
  105. EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kUnsafe);
  106. }
  107. // Tests that the platform-specific handle converted to read-only cannot be used
  108. // to perform a writable mapping with low-level system APIs like mmap().
  109. TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyHandleIsNotWritable) {
  110. PlatformSharedMemoryRegion region =
  111. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  112. ASSERT_TRUE(region.IsValid());
  113. EXPECT_TRUE(region.ConvertToReadOnly());
  114. EXPECT_EQ(region.GetMode(), PlatformSharedMemoryRegion::Mode::kReadOnly);
  115. EXPECT_TRUE(
  116. CheckReadOnlyPlatformSharedMemoryRegionForTesting(std::move(region)));
  117. }
  118. // Tests that the PassPlatformHandle() call invalidates the region.
  119. TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterPass) {
  120. PlatformSharedMemoryRegion region =
  121. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  122. ASSERT_TRUE(region.IsValid());
  123. std::ignore = region.PassPlatformHandle();
  124. EXPECT_FALSE(region.IsValid());
  125. }
  126. // Tests that the region is invalid after move.
  127. TEST_F(PlatformSharedMemoryRegionTest, InvalidAfterMove) {
  128. PlatformSharedMemoryRegion region =
  129. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  130. ASSERT_TRUE(region.IsValid());
  131. PlatformSharedMemoryRegion moved_region = std::move(region);
  132. EXPECT_FALSE(region.IsValid());
  133. EXPECT_TRUE(moved_region.IsValid());
  134. }
  135. // Tests that calling Take() with the size parameter equal to zero returns an
  136. // invalid region.
  137. TEST_F(PlatformSharedMemoryRegionTest, TakeRegionOfZeroSizeIsInvalid) {
  138. PlatformSharedMemoryRegion region =
  139. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  140. ASSERT_TRUE(region.IsValid());
  141. PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
  142. region.PassPlatformHandle(), region.GetMode(), 0, region.GetGUID());
  143. EXPECT_FALSE(region2.IsValid());
  144. }
  145. // Tests that calling Take() with the size parameter bigger than the integer max
  146. // value returns an invalid region.
  147. TEST_F(PlatformSharedMemoryRegionTest, TakeTooLargeRegionIsInvalid) {
  148. PlatformSharedMemoryRegion region =
  149. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  150. ASSERT_TRUE(region.IsValid());
  151. PlatformSharedMemoryRegion region2 = PlatformSharedMemoryRegion::Take(
  152. region.PassPlatformHandle(), region.GetMode(),
  153. static_cast<size_t>(std::numeric_limits<int>::max()) + 1,
  154. region.GetGUID());
  155. EXPECT_FALSE(region2.IsValid());
  156. }
  157. // Tests that mapping zero bytes fails.
  158. TEST_F(PlatformSharedMemoryRegionTest, MapAtZeroBytesTest) {
  159. PlatformSharedMemoryRegion region =
  160. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  161. ASSERT_TRUE(region.IsValid());
  162. WritableSharedMemoryMapping mapping = MapAtForTesting(&region, 0, 0);
  163. EXPECT_FALSE(mapping.IsValid());
  164. }
  165. // Tests that mapping bytes out of the region limits fails.
  166. TEST_F(PlatformSharedMemoryRegionTest, MapAtOutOfTheRegionLimitsTest) {
  167. PlatformSharedMemoryRegion region =
  168. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  169. ASSERT_TRUE(region.IsValid());
  170. WritableSharedMemoryMapping mapping =
  171. MapAtForTesting(&region, 0, region.GetSize() + 1);
  172. EXPECT_FALSE(mapping.IsValid());
  173. }
  174. // Tests that mapping with a size and offset causing overflow fails.
  175. TEST_F(PlatformSharedMemoryRegionTest, MapAtWithOverflowTest) {
  176. PlatformSharedMemoryRegion region =
  177. PlatformSharedMemoryRegion::CreateWritable(
  178. SysInfo::VMAllocationGranularity() * 2);
  179. ASSERT_TRUE(region.IsValid());
  180. size_t size = std::numeric_limits<size_t>::max();
  181. size_t offset = SysInfo::VMAllocationGranularity();
  182. // |size| + |offset| should be below the region size due to overflow but
  183. // mapping a region with these parameters should be invalid.
  184. EXPECT_LT(size + offset, region.GetSize());
  185. WritableSharedMemoryMapping mapping = MapAtForTesting(&region, offset, size);
  186. EXPECT_FALSE(mapping.IsValid());
  187. }
  188. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
  189. // Tests that the second handle is closed after a conversion to read-only on
  190. // POSIX.
  191. TEST_F(PlatformSharedMemoryRegionTest,
  192. ConvertToReadOnlyInvalidatesSecondHandle) {
  193. PlatformSharedMemoryRegion region =
  194. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  195. ASSERT_TRUE(region.IsValid());
  196. ASSERT_TRUE(region.ConvertToReadOnly());
  197. FDPair fds = region.GetPlatformHandle();
  198. EXPECT_LT(fds.readonly_fd, 0);
  199. }
  200. // Tests that the second handle is closed after a conversion to unsafe on
  201. // POSIX.
  202. TEST_F(PlatformSharedMemoryRegionTest, ConvertToUnsafeInvalidatesSecondHandle) {
  203. PlatformSharedMemoryRegion region =
  204. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  205. ASSERT_TRUE(region.IsValid());
  206. ASSERT_TRUE(region.ConvertToUnsafe());
  207. FDPair fds = region.GetPlatformHandle();
  208. EXPECT_LT(fds.readonly_fd, 0);
  209. }
  210. #endif
  211. void CheckReadOnlyMapProtection(void* addr) {
  212. #if BUILDFLAG(IS_APPLE)
  213. vm_region_basic_info_64 basic_info;
  214. vm_size_t dummy_size = 0;
  215. mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
  216. mach_port_t object_name;
  217. kern_return_t kr = vm_region_64(
  218. mach_task_self(), reinterpret_cast<vm_address_t*>(&addr), &dummy_size,
  219. VM_REGION_BASIC_INFO_64, reinterpret_cast<vm_region_info_t>(&basic_info),
  220. &info_count, &object_name);
  221. mach_port_deallocate(mach_task_self(), object_name);
  222. ASSERT_EQ(kr, KERN_SUCCESS);
  223. EXPECT_EQ(basic_info.protection & VM_PROT_ALL, VM_PROT_READ);
  224. EXPECT_EQ(basic_info.max_protection & VM_PROT_ALL, VM_PROT_READ);
  225. #elif BUILDFLAG(IS_POSIX)
  226. std::string proc_maps;
  227. ASSERT_TRUE(base::debug::ReadProcMaps(&proc_maps));
  228. std::vector<base::debug::MappedMemoryRegion> regions;
  229. ASSERT_TRUE(base::debug::ParseProcMaps(proc_maps, &regions));
  230. auto it = ranges::find_if(
  231. regions, [addr](const base::debug::MappedMemoryRegion& region) {
  232. return region.start == reinterpret_cast<uintptr_t>(addr);
  233. });
  234. ASSERT_TRUE(it != regions.end());
  235. // PROT_READ may imply PROT_EXEC on some architectures, so just check that
  236. // permissions don't contain PROT_WRITE bit.
  237. EXPECT_FALSE(it->permissions & base::debug::MappedMemoryRegion::WRITE);
  238. #elif BUILDFLAG(IS_WIN)
  239. MEMORY_BASIC_INFORMATION memory_info;
  240. size_t result = VirtualQueryEx(GetCurrentProcess(), addr, &memory_info,
  241. sizeof(memory_info));
  242. ASSERT_GT(result, 0ULL) << "Failed executing VirtualQueryEx "
  243. << logging::SystemErrorCodeToString(
  244. logging::GetLastSystemErrorCode());
  245. EXPECT_EQ(memory_info.AllocationProtect, static_cast<DWORD>(PAGE_READONLY));
  246. EXPECT_EQ(memory_info.Protect, static_cast<DWORD>(PAGE_READONLY));
  247. #elif BUILDFLAG(IS_FUCHSIA)
  248. // TODO(alexilin): We cannot call zx_object_get_info ZX_INFO_PROCESS_MAPS in
  249. // this process. Consider to create an auxiliary process that will read the
  250. // test process maps.
  251. #endif
  252. }
  253. bool TryToRestoreWritablePermissions(void* addr, size_t len) {
  254. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_IOS)
  255. int result = mprotect(addr, len, PROT_READ | PROT_WRITE);
  256. return result != -1;
  257. #elif BUILDFLAG(IS_WIN)
  258. DWORD old_protection;
  259. return VirtualProtect(addr, len, PAGE_READWRITE, &old_protection);
  260. #elif BUILDFLAG(IS_FUCHSIA)
  261. zx_status_t status =
  262. zx::vmar::root_self()->protect(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
  263. reinterpret_cast<uintptr_t>(addr), len);
  264. return status == ZX_OK;
  265. #else
  266. return false;
  267. #endif
  268. }
  269. // Tests that protection bits are set correctly for read-only region.
  270. TEST_F(PlatformSharedMemoryRegionTest, MappingProtectionSetCorrectly) {
  271. PlatformSharedMemoryRegion region =
  272. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  273. ASSERT_TRUE(region.IsValid());
  274. ASSERT_TRUE(region.ConvertToReadOnly());
  275. WritableSharedMemoryMapping ro_mapping = MapForTesting(&region);
  276. ASSERT_TRUE(ro_mapping.IsValid());
  277. CheckReadOnlyMapProtection(ro_mapping.memory());
  278. EXPECT_FALSE(TryToRestoreWritablePermissions(ro_mapping.memory(),
  279. ro_mapping.mapped_size()));
  280. CheckReadOnlyMapProtection(ro_mapping.memory());
  281. }
  282. // Tests that platform handle permissions are checked correctly.
  283. TEST_F(PlatformSharedMemoryRegionTest,
  284. CheckPlatformHandlePermissionsCorrespondToMode) {
  285. using Mode = PlatformSharedMemoryRegion::Mode;
  286. auto check = [](const PlatformSharedMemoryRegion& region,
  287. PlatformSharedMemoryRegion::Mode mode) {
  288. return PlatformSharedMemoryRegion::
  289. CheckPlatformHandlePermissionsCorrespondToMode(
  290. region.GetPlatformHandle(), mode, region.GetSize());
  291. };
  292. // Check kWritable region.
  293. PlatformSharedMemoryRegion region =
  294. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  295. ASSERT_TRUE(region.IsValid());
  296. EXPECT_TRUE(check(region, Mode::kWritable));
  297. EXPECT_FALSE(check(region, Mode::kReadOnly));
  298. // Check kReadOnly region.
  299. ASSERT_TRUE(region.ConvertToReadOnly());
  300. EXPECT_TRUE(check(region, Mode::kReadOnly));
  301. EXPECT_FALSE(check(region, Mode::kWritable));
  302. EXPECT_FALSE(check(region, Mode::kUnsafe));
  303. // Check kUnsafe region.
  304. PlatformSharedMemoryRegion region2 =
  305. PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
  306. ASSERT_TRUE(region2.IsValid());
  307. EXPECT_TRUE(check(region2, Mode::kUnsafe));
  308. EXPECT_FALSE(check(region2, Mode::kReadOnly));
  309. }
  310. // Tests that it's impossible to create read-only platform shared memory region.
  311. TEST_F(PlatformSharedMemoryRegionTest, CreateReadOnlyRegionDeathTest) {
  312. #ifdef OFFICIAL_BUILD
  313. // The official build does not print the reason a CHECK failed.
  314. const char kErrorRegex[] = "";
  315. #else
  316. const char kErrorRegex[] =
  317. "Creating a region in read-only mode will lead to this region being "
  318. "non-modifiable";
  319. #endif
  320. EXPECT_DEATH_IF_SUPPORTED(
  321. PlatformSharedMemoryRegion::Create(
  322. PlatformSharedMemoryRegion::Mode::kReadOnly, kRegionSize),
  323. kErrorRegex);
  324. }
  325. // Tests that it's prohibited to duplicate a writable region.
  326. TEST_F(PlatformSharedMemoryRegionTest, DuplicateWritableRegionDeathTest) {
  327. #ifdef OFFICIAL_BUILD
  328. const char kErrorRegex[] = "";
  329. #else
  330. const char kErrorRegex[] =
  331. "Duplicating a writable shared memory region is prohibited";
  332. #endif
  333. PlatformSharedMemoryRegion region =
  334. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  335. ASSERT_TRUE(region.IsValid());
  336. EXPECT_DEATH_IF_SUPPORTED(region.Duplicate(), kErrorRegex);
  337. }
  338. // Tests that it's prohibited to convert an unsafe region to read-only.
  339. TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToReadOnlyDeathTest) {
  340. #ifdef OFFICIAL_BUILD
  341. const char kErrorRegex[] = "";
  342. #else
  343. const char kErrorRegex[] =
  344. "Only writable shared memory region can be converted to read-only";
  345. #endif
  346. PlatformSharedMemoryRegion region =
  347. PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
  348. ASSERT_TRUE(region.IsValid());
  349. EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
  350. }
  351. // Tests that it's prohibited to convert a read-only region to read-only.
  352. TEST_F(PlatformSharedMemoryRegionTest,
  353. ReadOnlyRegionConvertToReadOnlyDeathTest) {
  354. #ifdef OFFICIAL_BUILD
  355. const char kErrorRegex[] = "";
  356. #else
  357. const char kErrorRegex[] =
  358. "Only writable shared memory region can be converted to read-only";
  359. #endif
  360. PlatformSharedMemoryRegion region =
  361. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  362. ASSERT_TRUE(region.IsValid());
  363. EXPECT_TRUE(region.ConvertToReadOnly());
  364. EXPECT_DEATH_IF_SUPPORTED(region.ConvertToReadOnly(), kErrorRegex);
  365. }
  366. // Tests that it's prohibited to convert a read-only region to unsafe.
  367. TEST_F(PlatformSharedMemoryRegionTest, ReadOnlyRegionConvertToUnsafeDeathTest) {
  368. #ifdef OFFICIAL_BUILD
  369. const char kErrorRegex[] = "";
  370. #else
  371. const char kErrorRegex[] =
  372. "Only writable shared memory region can be converted to unsafe";
  373. #endif
  374. PlatformSharedMemoryRegion region =
  375. PlatformSharedMemoryRegion::CreateWritable(kRegionSize);
  376. ASSERT_TRUE(region.IsValid());
  377. ASSERT_TRUE(region.ConvertToReadOnly());
  378. EXPECT_DEATH_IF_SUPPORTED(region.ConvertToUnsafe(), kErrorRegex);
  379. }
  380. // Tests that it's prohibited to convert an unsafe region to unsafe.
  381. TEST_F(PlatformSharedMemoryRegionTest, UnsafeRegionConvertToUnsafeDeathTest) {
  382. #ifdef OFFICIAL_BUILD
  383. const char kErrorRegex[] = "";
  384. #else
  385. const char kErrorRegex[] =
  386. "Only writable shared memory region can be converted to unsafe";
  387. #endif
  388. PlatformSharedMemoryRegion region =
  389. PlatformSharedMemoryRegion::CreateUnsafe(kRegionSize);
  390. ASSERT_TRUE(region.IsValid());
  391. EXPECT_DEATH_IF_SUPPORTED(region.ConvertToUnsafe(), kErrorRegex);
  392. }
  393. } // namespace subtle
  394. } // namespace base