1 // Copyright 2024 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "base/memory/protected_memory.h"
11
12 #include <stddef.h>
13 #include <stdint.h>
14
15 #include <climits>
16 #include <type_traits>
17
18 #include "base/memory/protected_memory_buildflags.h"
19 #include "base/synchronization/lock.h"
20 #include "base/test/gtest_util.h"
21 #include "build/build_config.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace base {
25 namespace {
26
27 struct Data {
28 Data() = default;
Database::__anondf54bf8e0111::Data29 constexpr Data(int16_t f, int32_t b) : foo(f), bar(b) {}
30 int16_t foo = 0;
31 int32_t bar = -1;
32 };
33
34 struct DataWithNonTrivialConstructor {
DataWithNonTrivialConstructorbase::__anondf54bf8e0111::DataWithNonTrivialConstructor35 explicit DataWithNonTrivialConstructor(int f) : foo(f) {}
36 int foo;
37 };
38
39 static_assert(
40 !std::is_trivially_constructible_v<DataWithNonTrivialConstructor>);
41
42 #if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
VerifyByteSequenceIsNotWriteable(unsigned char * const byte_pattern,const size_t number_of_bits,const size_t bit_increment)43 void VerifyByteSequenceIsNotWriteable(unsigned char* const byte_pattern,
44 const size_t number_of_bits,
45 const size_t bit_increment) {
46 const auto check_bit_not_writeable = [=](const size_t bit_index) {
47 const size_t byte_index = bit_index / CHAR_BIT;
48 const size_t local_bit_index = bit_index % CHAR_BIT;
49
50 EXPECT_CHECK_DEATH_WITH(
51 byte_pattern[byte_index] ^= (0x1 << local_bit_index), "")
52 << " at bit " << bit_index << " of " << number_of_bits;
53 };
54
55 // Check the boundary bits explicitly to ensure we cover these.
56 if (number_of_bits >= 1) {
57 check_bit_not_writeable(0);
58 }
59
60 if (number_of_bits >= 2) {
61 check_bit_not_writeable(number_of_bits - 1);
62 }
63
64 // Now check the bits in between at the requested increment.
65 for (size_t bit_index = bit_increment; bit_index < (number_of_bits - 1);
66 bit_index += bit_increment) {
67 check_bit_not_writeable(bit_index);
68 }
69 }
70
71 template <typename T>
VerifyInstanceIsNotWriteable(T & instance,const size_t bit_increment=3)72 void VerifyInstanceIsNotWriteable(T& instance, const size_t bit_increment = 3) {
73 VerifyByteSequenceIsNotWriteable(
74 reinterpret_cast<unsigned char*>(std::addressof(instance)),
75 sizeof(T) * CHAR_BIT, bit_increment);
76 }
77 #endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
78
79 DEFINE_PROTECTED_DATA ProtectedMemory<int> g_explicit_initialization;
80
TEST(ProtectedMemoryTest,ExplicitInitializationWithExplicitValue)81 TEST(ProtectedMemoryTest, ExplicitInitializationWithExplicitValue) {
82 static ProtectedMemoryInitializer initializer_explicit_value(
83 g_explicit_initialization, 4);
84
85 EXPECT_EQ(*g_explicit_initialization, 4);
86 }
87
88 DEFINE_PROTECTED_DATA ProtectedMemory<int>
89 g_explicit_initialization_with_default_value;
90
TEST(ProtectedMemoryTest,VerifyExplicitInitializationWithDefaultValue)91 TEST(ProtectedMemoryTest, VerifyExplicitInitializationWithDefaultValue) {
92 static ProtectedMemoryInitializer initializer_explicit_value(
93 g_explicit_initialization_with_default_value);
94
95 EXPECT_EQ(*g_explicit_initialization_with_default_value, int());
96 }
97
98 DEFINE_PROTECTED_DATA
99 ProtectedMemory<DataWithNonTrivialConstructor>
100 g_lazily_initialized_with_explicit_initialization;
101
TEST(ProtectedMemoryTest,ExplicitLazyInitializationWithExplicitValue)102 TEST(ProtectedMemoryTest, ExplicitLazyInitializationWithExplicitValue) {
103 static ProtectedMemoryInitializer initializer_explicit_value(
104 g_lazily_initialized_with_explicit_initialization, 4);
105
106 EXPECT_EQ(g_lazily_initialized_with_explicit_initialization->foo, 4);
107 }
108
109 DEFINE_PROTECTED_DATA
110 ProtectedMemory<DataWithNonTrivialConstructor> g_uninitialized;
111
TEST(ProtectedMemoryDeathTest,AccessWithoutInitialization)112 TEST(ProtectedMemoryDeathTest, AccessWithoutInitialization) {
113 EXPECT_CHECK_DEATH_WITH(g_uninitialized.operator*(), "");
114 EXPECT_CHECK_DEATH_WITH(g_uninitialized.operator->(), "");
115 }
116
117 #if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
118 DEFINE_PROTECTED_DATA ProtectedMemory<Data> g_initialized;
119
TEST(ProtectedMemoryTest,VerifySetValue)120 TEST(ProtectedMemoryTest, VerifySetValue) {
121 static ProtectedMemoryInitializer initializer_explicit_value(g_initialized);
122 ASSERT_NE(g_initialized->foo, 5);
123 EXPECT_EQ(g_initialized->bar, -1);
124 {
125 base::AutoWritableMemory writer(g_initialized);
126 writer.GetProtectedDataPtr()->foo = 5;
127 }
128 EXPECT_EQ(g_initialized->foo, 5);
129 EXPECT_EQ(g_initialized->bar, -1);
130 }
131
132 DEFINE_PROTECTED_DATA ProtectedMemory<Data> g_not_writable;
133
TEST(ProtectedMemoryDeathTest,AccessWithoutWriteAccessCrashes)134 TEST(ProtectedMemoryDeathTest, AccessWithoutWriteAccessCrashes) {
135 static ProtectedMemoryInitializer initializer_explicit_value(g_not_writable);
136 VerifyInstanceIsNotWriteable(g_not_writable);
137 }
138
TEST(ProtectedMemoryDeathTest,FailsIfDefinedOutsideOfProtectMemoryRegion)139 TEST(ProtectedMemoryDeathTest, FailsIfDefinedOutsideOfProtectMemoryRegion) {
140 ProtectedMemory<Data> data;
141 EXPECT_CHECK_DEATH({ AutoWritableMemory writer(data); });
142 }
143
144 #endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
145
146 } // namespace
147 } // namespace base
148