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