v8_platform_page_allocator_unittest.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright 2021 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 "gin/v8_platform_page_allocator.h"
  5. #include "base/cpu.h"
  6. #include "build/build_config.h"
  7. #include "testing/gtest/include/gtest/gtest.h"
  8. // includes for Branch Target Instruction tests
  9. #if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
  10. // BTI is only available for AArch64, relevant platform are Android and Linux
  11. #include "base/allocator/partition_allocator/arm_bti_test_functions.h"
  12. #include "base/allocator/partition_allocator/page_allocator_constants.h"
  13. #if BUILDFLAG(IS_POSIX)
  14. #include <signal.h>
  15. #include "testing/gtest/include/gtest/gtest-death-test.h"
  16. #endif
  17. #endif // defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
  18. namespace gin {
  19. TEST(V8PlatformPageAllocatorTest, VerifyGetPageConfig) {
  20. auto sut = gin::PageAllocator();
  21. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kNoAccess),
  22. partition_alloc::PageAccessibilityConfiguration::kInaccessible);
  23. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kRead),
  24. partition_alloc::PageAccessibilityConfiguration::kRead);
  25. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadWrite),
  26. partition_alloc::PageAccessibilityConfiguration::kReadWrite);
  27. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadWriteExecute),
  28. partition_alloc::PageAccessibilityConfiguration::kReadWriteExecute);
  29. #if defined(__ARM_FEATURE_BTI_DEFAULT)
  30. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
  31. base::CPU::GetInstanceNoAllocation().has_bti()
  32. ? partition_alloc::PageAccessibilityConfiguration::
  33. kReadExecuteProtected
  34. : partition_alloc::PageAccessibilityConfiguration::kReadExecute);
  35. #else
  36. CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
  37. partition_alloc::PageAccessibilityConfiguration::kReadExecute);
  38. #endif
  39. CHECK_EQ(
  40. sut.GetPageConfigForTesting(v8::PageAllocator::kNoAccessWillJitLater),
  41. partition_alloc::PageAccessibilityConfiguration::kInaccessible);
  42. }
  43. #if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
  44. using BTITestFunction = int64_t (*)(int64_t);
  45. TEST(V8PlatformPageAllocatorBTITest, VerifyReadExecutePagesAreProtected) {
  46. auto page_allocator = gin::PageAllocator();
  47. auto const memory_size =
  48. partition_alloc::internal::PageAllocationGranularity();
  49. auto const memory_alignment =
  50. partition_alloc::internal::PageAllocationGranularity();
  51. // Next, map some read-write memory and copy some test helper functions there.
  52. char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages(
  53. nullptr, memory_size, memory_alignment,
  54. v8::PageAllocator::Permission::kReadWriteExecute));
  55. ptrdiff_t const function_range =
  56. reinterpret_cast<char*>(arm_bti_test_function_end) -
  57. reinterpret_cast<char*>(arm_bti_test_function);
  58. ptrdiff_t const invalid_offset =
  59. reinterpret_cast<char*>(arm_bti_test_function_invalid_offset) -
  60. reinterpret_cast<char*>(arm_bti_test_function);
  61. // ensure alignment to 4 bytes required by function call convention
  62. EXPECT_EQ(0u, ((uint64_t)buffer) % 4);
  63. EXPECT_EQ(0u, ((uint64_t)function_range) % 4);
  64. EXPECT_EQ(0u, ((uint64_t)invalid_offset) % 4);
  65. memcpy(buffer, reinterpret_cast<void*>(arm_bti_test_function),
  66. function_range);
  67. // Next re-protect the page to the permission level to test
  68. page_allocator.SetPermissions(buffer, memory_size,
  69. v8::PageAllocator::Permission::kReadExecute);
  70. // Attempt to call a function with BTI landing pad.
  71. BTITestFunction const bti_enabled_fn =
  72. reinterpret_cast<BTITestFunction>(buffer);
  73. // bti_enabled_fn must return 18, no matter if BTI is actually enabled or not.
  74. EXPECT_EQ(bti_enabled_fn(15), 18);
  75. // Next, attempt to call a function without BTI landing pad.
  76. BTITestFunction const bti_invalid_fn =
  77. reinterpret_cast<BTITestFunction>(buffer + invalid_offset);
  78. // Expectation for behaviour of bti_invalid_fn depends on the capabilities of
  79. // the actual CPU we are running on. The code that were are trying to execute
  80. // is assembly code and always has BTI enabled.
  81. if (base::CPU::GetInstanceNoAllocation().has_bti()) {
  82. #if BUILDFLAG(IS_POSIX) // signal handling is available on POSIX compliant
  83. // systems only
  84. EXPECT_EXIT({ bti_invalid_fn(15); }, testing::KilledBySignal(SIGILL),
  85. ""); // Should crash with SIGILL.
  86. #endif // BUILDFLAG(IS_POSIX)
  87. } else {
  88. EXPECT_EQ(bti_invalid_fn(15), 17);
  89. }
  90. page_allocator.FreePages(buffer, memory_size);
  91. }
  92. TEST(V8PlatformAllocatorBTITest, VerifyReadWriteExecutePagesAreNotProtected) {
  93. auto page_allocator = gin::PageAllocator();
  94. auto const memory_size =
  95. partition_alloc::internal::PageAllocationGranularity();
  96. auto const memory_alignment =
  97. partition_alloc::internal::PageAllocationGranularity();
  98. // Next, map some read-write memory and copy some test helper functions there.
  99. char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages(
  100. nullptr, memory_size, memory_alignment,
  101. v8::PageAllocator::Permission::kReadWriteExecute));
  102. ptrdiff_t const function_range =
  103. reinterpret_cast<char*>(arm_bti_test_function_end) -
  104. reinterpret_cast<char*>(arm_bti_test_function);
  105. ptrdiff_t const invalid_offset =
  106. reinterpret_cast<char*>(arm_bti_test_function_invalid_offset) -
  107. reinterpret_cast<char*>(arm_bti_test_function);
  108. // ensure alignment to 4 bytes required by function call convention
  109. EXPECT_EQ(0u, ((uint64_t)buffer) % 4);
  110. EXPECT_EQ(0u, ((uint64_t)function_range) % 4);
  111. EXPECT_EQ(0u, ((uint64_t)invalid_offset) % 4);
  112. memcpy(buffer, reinterpret_cast<void*>(arm_bti_test_function),
  113. function_range);
  114. // Attempt to call a function with BTI landing pad.
  115. BTITestFunction const bti_enabled_fn =
  116. reinterpret_cast<BTITestFunction>(buffer);
  117. // bti_enabled_fn must return 18, no matter if BTI is actually enabled or not.
  118. EXPECT_EQ(bti_enabled_fn(15), 18);
  119. // Next, attempt to call a function without BTI landing pad.
  120. BTITestFunction const bti_invalid_fn =
  121. reinterpret_cast<BTITestFunction>(buffer + invalid_offset);
  122. // Since permission kReadWriteExecute wont actually cause BTI to be enabled
  123. // for the allocated page, calling this function must return without error.
  124. EXPECT_EQ(bti_invalid_fn(15), 17);
  125. page_allocator.FreePages(buffer, memory_size);
  126. }
  127. #endif // if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
  128. } // namespace gin