123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- // Copyright 2021 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "gin/v8_platform_page_allocator.h"
- #include "base/cpu.h"
- #include "build/build_config.h"
- #include "testing/gtest/include/gtest/gtest.h"
- // includes for Branch Target Instruction tests
- #if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
- // BTI is only available for AArch64, relevant platform are Android and Linux
- #include "base/allocator/partition_allocator/arm_bti_test_functions.h"
- #include "base/allocator/partition_allocator/page_allocator_constants.h"
- #if BUILDFLAG(IS_POSIX)
- #include <signal.h>
- #include "testing/gtest/include/gtest/gtest-death-test.h"
- #endif
- #endif // defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
- namespace gin {
- TEST(V8PlatformPageAllocatorTest, VerifyGetPageConfig) {
- auto sut = gin::PageAllocator();
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kNoAccess),
- partition_alloc::PageAccessibilityConfiguration::kInaccessible);
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kRead),
- partition_alloc::PageAccessibilityConfiguration::kRead);
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadWrite),
- partition_alloc::PageAccessibilityConfiguration::kReadWrite);
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadWriteExecute),
- partition_alloc::PageAccessibilityConfiguration::kReadWriteExecute);
- #if defined(__ARM_FEATURE_BTI_DEFAULT)
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
- base::CPU::GetInstanceNoAllocation().has_bti()
- ? partition_alloc::PageAccessibilityConfiguration::
- kReadExecuteProtected
- : partition_alloc::PageAccessibilityConfiguration::kReadExecute);
- #else
- CHECK_EQ(sut.GetPageConfigForTesting(v8::PageAllocator::kReadExecute),
- partition_alloc::PageAccessibilityConfiguration::kReadExecute);
- #endif
- CHECK_EQ(
- sut.GetPageConfigForTesting(v8::PageAllocator::kNoAccessWillJitLater),
- partition_alloc::PageAccessibilityConfiguration::kInaccessible);
- }
- #if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
- using BTITestFunction = int64_t (*)(int64_t);
- TEST(V8PlatformPageAllocatorBTITest, VerifyReadExecutePagesAreProtected) {
- auto page_allocator = gin::PageAllocator();
- auto const memory_size =
- partition_alloc::internal::PageAllocationGranularity();
- auto const memory_alignment =
- partition_alloc::internal::PageAllocationGranularity();
- // Next, map some read-write memory and copy some test helper functions there.
- char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages(
- nullptr, memory_size, memory_alignment,
- v8::PageAllocator::Permission::kReadWriteExecute));
- ptrdiff_t const function_range =
- reinterpret_cast<char*>(arm_bti_test_function_end) -
- reinterpret_cast<char*>(arm_bti_test_function);
- ptrdiff_t const invalid_offset =
- reinterpret_cast<char*>(arm_bti_test_function_invalid_offset) -
- reinterpret_cast<char*>(arm_bti_test_function);
- // ensure alignment to 4 bytes required by function call convention
- EXPECT_EQ(0u, ((uint64_t)buffer) % 4);
- EXPECT_EQ(0u, ((uint64_t)function_range) % 4);
- EXPECT_EQ(0u, ((uint64_t)invalid_offset) % 4);
- memcpy(buffer, reinterpret_cast<void*>(arm_bti_test_function),
- function_range);
- // Next re-protect the page to the permission level to test
- page_allocator.SetPermissions(buffer, memory_size,
- v8::PageAllocator::Permission::kReadExecute);
- // Attempt to call a function with BTI landing pad.
- BTITestFunction const bti_enabled_fn =
- reinterpret_cast<BTITestFunction>(buffer);
- // bti_enabled_fn must return 18, no matter if BTI is actually enabled or not.
- EXPECT_EQ(bti_enabled_fn(15), 18);
- // Next, attempt to call a function without BTI landing pad.
- BTITestFunction const bti_invalid_fn =
- reinterpret_cast<BTITestFunction>(buffer + invalid_offset);
- // Expectation for behaviour of bti_invalid_fn depends on the capabilities of
- // the actual CPU we are running on. The code that were are trying to execute
- // is assembly code and always has BTI enabled.
- if (base::CPU::GetInstanceNoAllocation().has_bti()) {
- #if BUILDFLAG(IS_POSIX) // signal handling is available on POSIX compliant
- // systems only
- EXPECT_EXIT({ bti_invalid_fn(15); }, testing::KilledBySignal(SIGILL),
- ""); // Should crash with SIGILL.
- #endif // BUILDFLAG(IS_POSIX)
- } else {
- EXPECT_EQ(bti_invalid_fn(15), 17);
- }
- page_allocator.FreePages(buffer, memory_size);
- }
- TEST(V8PlatformAllocatorBTITest, VerifyReadWriteExecutePagesAreNotProtected) {
- auto page_allocator = gin::PageAllocator();
- auto const memory_size =
- partition_alloc::internal::PageAllocationGranularity();
- auto const memory_alignment =
- partition_alloc::internal::PageAllocationGranularity();
- // Next, map some read-write memory and copy some test helper functions there.
- char* const buffer = reinterpret_cast<char*>(page_allocator.AllocatePages(
- nullptr, memory_size, memory_alignment,
- v8::PageAllocator::Permission::kReadWriteExecute));
- ptrdiff_t const function_range =
- reinterpret_cast<char*>(arm_bti_test_function_end) -
- reinterpret_cast<char*>(arm_bti_test_function);
- ptrdiff_t const invalid_offset =
- reinterpret_cast<char*>(arm_bti_test_function_invalid_offset) -
- reinterpret_cast<char*>(arm_bti_test_function);
- // ensure alignment to 4 bytes required by function call convention
- EXPECT_EQ(0u, ((uint64_t)buffer) % 4);
- EXPECT_EQ(0u, ((uint64_t)function_range) % 4);
- EXPECT_EQ(0u, ((uint64_t)invalid_offset) % 4);
- memcpy(buffer, reinterpret_cast<void*>(arm_bti_test_function),
- function_range);
- // Attempt to call a function with BTI landing pad.
- BTITestFunction const bti_enabled_fn =
- reinterpret_cast<BTITestFunction>(buffer);
- // bti_enabled_fn must return 18, no matter if BTI is actually enabled or not.
- EXPECT_EQ(bti_enabled_fn(15), 18);
- // Next, attempt to call a function without BTI landing pad.
- BTITestFunction const bti_invalid_fn =
- reinterpret_cast<BTITestFunction>(buffer + invalid_offset);
- // Since permission kReadWriteExecute wont actually cause BTI to be enabled
- // for the allocated page, calling this function must return without error.
- EXPECT_EQ(bti_invalid_fn(15), 17);
- page_allocator.FreePages(buffer, memory_size);
- }
- #endif // if defined(ARCH_CPU_ARM64) && (OS_LINUX || OS_ANDROID)
- } // namespace gin
|