• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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