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