1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Protected memory is memory holding security-sensitive data intended to be 6 // left read-only for the majority of its lifetime to avoid being overwritten 7 // by attackers. ProtectedMemory is a simple wrapper around platform-specific 8 // APIs to set memory read-write and read-only when required. Protected memory 9 // should be set read-write for the minimum amount of time required. 10 11 // Normally mutable variables are held in read-write memory and constant data 12 // is held in read-only memory to ensure it is not accidentally overwritten. 13 // In some cases we want to hold mutable variables in read-only memory, except 14 // when they are being written to, to ensure that they are not tampered with. 15 // 16 // ProtectedMemory is a container class intended to hold a single variable in 17 // read-only memory, except when explicitly set read-write. The variable can be 18 // set read-write by creating a scoped AutoWritableMemory object by calling 19 // AutoWritableMemory::Create(), the memory stays writable until the returned 20 // object goes out of scope and is destructed. The wrapped variable can be 21 // accessed using operator* and operator->. 22 // 23 // Instances of ProtectedMemory must be declared in the PROTECTED_MEMORY_SECTION 24 // and as global variables. Because protected memory variables are globals, the 25 // the same rules apply disallowing non-trivial constructors and destructors. 26 // Global definitions are required to avoid the linker placing statics in 27 // inlinable functions into a comdat section and setting the protected memory 28 // section read-write when they are merged. 29 // 30 // EXAMPLE: 31 // 32 // struct Items { void* item1; }; 33 // static PROTECTED_MEMORY_SECTION base::ProtectedMemory<Items> items; 34 // void InitializeItems() { 35 // // Explicitly set items read-write before writing to it. 36 // auto writer = base::AutoWritableMemory::Create(items); 37 // items->item1 = /* ... */; 38 // assert(items->item1 != nullptr); 39 // // items is set back to read-only on the destruction of writer 40 // } 41 // 42 // using FnPtr = void (*)(void); 43 // PROTECTED_MEMORY_SECTION base::ProtectedMemory<FnPtr> fnPtr; 44 // FnPtr ResolveFnPtr(void) { 45 // // The Initializer nested class is a helper class for creating a static 46 // // initializer for a ProtectedMemory variable. It implicitly sets the 47 // // variable read-write during initialization. 48 // static base::ProtectedMemory<FnPtr>::Initializer I(&fnPtr, 49 // reinterpret_cast<FnPtr>(dlsym(/* ... */))); 50 // return *fnPtr; 51 // } 52 53 #ifndef BASE_MEMORY_PROTECTED_MEMORY_H_ 54 #define BASE_MEMORY_PROTECTED_MEMORY_H_ 55 56 #include "base/lazy_instance.h" 57 #include "base/logging.h" 58 #include "base/macros.h" 59 #include "base/memory/protected_memory_buildflags.h" 60 #include "base/synchronization/lock.h" 61 #include "build/build_config.h" 62 63 #define PROTECTED_MEMORY_ENABLED 1 64 65 // Linking with lld is required to workaround crbug.com/792777. 66 // TODO(vtsyrklevich): Remove once support for gold on Android/CrOs is dropped 67 #if defined(OS_LINUX) && BUILDFLAG(USE_LLD) 68 // Define the section read-only 69 __asm__(".section protected_memory, \"a\"\n\t"); 70 #define PROTECTED_MEMORY_SECTION __attribute__((section("protected_memory"))) 71 72 // Explicitly mark these variables hidden so the symbols are local to the 73 // currently built component. Otherwise they are created with global (external) 74 // linkage and component builds would break because a single pair of these 75 // symbols would override the rest. 76 __attribute__((visibility("hidden"))) extern char __start_protected_memory; 77 __attribute__((visibility("hidden"))) extern char __stop_protected_memory; 78 79 #elif defined(OS_MACOSX) && !defined(OS_IOS) 80 // The segment the section is in is defined read-only with a linker flag in 81 // build/config/mac/BUILD.gn 82 #define PROTECTED_MEMORY_SECTION \ 83 __attribute__((section("PROTECTED_MEMORY, protected_memory"))) 84 extern char __start_protected_memory __asm( 85 "section$start$PROTECTED_MEMORY$protected_memory"); 86 extern char __stop_protected_memory __asm( 87 "section$end$PROTECTED_MEMORY$protected_memory"); 88 89 #elif defined(OS_WIN) 90 // Define a read-write prot section. The $a, $mem, and $z 'sub-sections' are 91 // merged alphabetically so $a and $z are used to define the start and end of 92 // the protected memory section, and $mem holds protected variables. 93 // (Note: Sections in Portable Executables are equivalent to segments in other 94 // executable formats, so this section is mapped into its own pages.) 95 #pragma section("prot$a", read, write) 96 #pragma section("prot$mem", read, write) 97 #pragma section("prot$z", read, write) 98 99 // We want the protected memory section to be read-only, not read-write so we 100 // instruct the linker to set the section read-only at link time. We do this 101 // at link time instead of compile time, because defining the prot section 102 // read-only would cause mis-compiles due to optimizations assuming that the 103 // section contents are constant. 104 #pragma comment(linker, "/SECTION:prot,R") 105 106 __declspec(allocate("prot$a")) __declspec(selectany) 107 char __start_protected_memory; 108 __declspec(allocate("prot$z")) __declspec(selectany) 109 char __stop_protected_memory; 110 111 #define PROTECTED_MEMORY_SECTION __declspec(allocate("prot$mem")) 112 113 #else 114 #undef PROTECTED_MEMORY_ENABLED 115 #define PROTECTED_MEMORY_ENABLED 0 116 #define PROTECTED_MEMORY_SECTION 117 #endif 118 119 namespace base { 120 121 template <typename T> 122 class ProtectedMemory { 123 public: 124 ProtectedMemory() = default; 125 126 // Expose direct access to the encapsulated variable 127 T& operator*() { return data; } 128 const T& operator*() const { return data; } 129 T* operator->() { return &data; } 130 const T* operator->() const { return &data; } 131 132 // Helper class for creating simple ProtectedMemory static initializers. 133 class Initializer { 134 public: 135 // Defined out-of-line below to break circular definition dependency between 136 // ProtectedMemory and AutoWritableMemory. 137 Initializer(ProtectedMemory<T>* PM, const T& Init); 138 139 DISALLOW_IMPLICIT_CONSTRUCTORS(Initializer); 140 }; 141 142 private: 143 T data; 144 145 DISALLOW_COPY_AND_ASSIGN(ProtectedMemory); 146 }; 147 148 // DCHECK that the byte at |ptr| is read-only. 149 BASE_EXPORT void AssertMemoryIsReadOnly(const void* ptr); 150 151 // Abstract out platform-specific methods to get the beginning and end of the 152 // PROTECTED_MEMORY_SECTION. ProtectedMemoryEnd returns a pointer to the byte 153 // past the end of the PROTECTED_MEMORY_SECTION. 154 #if PROTECTED_MEMORY_ENABLED 155 constexpr void* ProtectedMemoryStart = &__start_protected_memory; 156 constexpr void* ProtectedMemoryEnd = &__stop_protected_memory; 157 #endif 158 159 #if defined(COMPONENT_BUILD) 160 namespace internal { 161 162 // For component builds we want to define a separate global writers variable 163 // (explained below) in every DSO that includes this header. To do that we use 164 // this template to define a global without duplicate symbol errors. 165 template <typename T> 166 struct DsoSpecific { 167 static T value; 168 }; 169 template <typename T> 170 T DsoSpecific<T>::value = 0; 171 172 } // namespace internal 173 #endif // defined(COMPONENT_BUILD) 174 175 // A class that sets a given ProtectedMemory variable writable while the 176 // AutoWritableMemory is in scope. This class implements the logic for setting 177 // the protected memory region read-only/read-write in a thread-safe manner. 178 class AutoWritableMemory { 179 private: 180 // 'writers' is a global holding the number of ProtectedMemory instances set 181 // writable, used to avoid races setting protected memory readable/writable. 182 // When this reaches zero the protected memory region is set read only. 183 // Access is controlled by writers_lock. 184 #if defined(COMPONENT_BUILD) 185 // For component builds writers is a reference to an int defined separately in 186 // every DSO. 187 static constexpr int& writers = internal::DsoSpecific<int>::value; 188 #else 189 // Otherwise, we declare writers in the protected memory section to avoid the 190 // scenario where an attacker could overwrite it with a large value and invoke 191 // code that constructs and destructs an AutoWritableMemory. After such a call 192 // protected memory would still be set writable because writers > 0. 193 static int writers; 194 #endif // defined(COMPONENT_BUILD) 195 196 // Synchronizes access to the writers variable and the simultaneous actions 197 // that need to happen alongside writers changes, e.g. setting the protected 198 // memory region readable when writers is decremented to 0. 199 static BASE_EXPORT base::LazyInstance<Lock>::Leaky writers_lock; 200 201 // Abstract out platform-specific memory APIs. |end| points to the byte past 202 // the end of the region of memory having its memory protections changed. 203 BASE_EXPORT bool SetMemoryReadWrite(void* start, void* end); 204 BASE_EXPORT bool SetMemoryReadOnly(void* start, void* end); 205 206 // If this is the first writer (e.g. writers == 0) set the writers variable 207 // read-write. Next, increment writers and set the requested memory writable. 208 AutoWritableMemory(void* ptr, void* ptr_end) { 209 #if PROTECTED_MEMORY_ENABLED 210 DCHECK(ptr >= ProtectedMemoryStart && ptr_end <= ProtectedMemoryEnd); 211 212 { 213 base::AutoLock auto_lock(writers_lock.Get()); 214 if (writers == 0) { 215 AssertMemoryIsReadOnly(ptr); 216 #if !defined(COMPONENT_BUILD) 217 AssertMemoryIsReadOnly(&writers); 218 CHECK(SetMemoryReadWrite(&writers, &writers + 1)); 219 #endif // !defined(COMPONENT_BUILD) 220 } 221 222 writers++; 223 } 224 225 CHECK(SetMemoryReadWrite(ptr, ptr_end)); 226 #endif // PROTECTED_MEMORY_ENABLED 227 } 228 229 public: 230 // Wrap the private constructor to create an easy-to-use interface to 231 // construct AutoWritableMemory objects. 232 template <typename T> 233 static AutoWritableMemory Create(ProtectedMemory<T>& PM) { 234 T* ptr = &*PM; 235 return AutoWritableMemory(ptr, ptr + 1); 236 } 237 238 // Move constructor just increments writers 239 AutoWritableMemory(AutoWritableMemory&& original) { 240 #if PROTECTED_MEMORY_ENABLED 241 base::AutoLock auto_lock(writers_lock.Get()); 242 CHECK_GT(writers, 0); 243 writers++; 244 #endif // PROTECTED_MEMORY_ENABLED 245 } 246 247 // On destruction decrement writers, and if no other writers exist, set the 248 // entire protected memory region read-only. 249 ~AutoWritableMemory() { 250 #if PROTECTED_MEMORY_ENABLED 251 base::AutoLock auto_lock(writers_lock.Get()); 252 CHECK_GT(writers, 0); 253 writers--; 254 255 if (writers == 0) { 256 CHECK(SetMemoryReadOnly(ProtectedMemoryStart, ProtectedMemoryEnd)); 257 #if !defined(COMPONENT_BUILD) 258 AssertMemoryIsReadOnly(&writers); 259 #endif // !defined(COMPONENT_BUILD) 260 } 261 #endif // PROTECTED_MEMORY_ENABLED 262 } 263 264 DISALLOW_IMPLICIT_CONSTRUCTORS(AutoWritableMemory); 265 }; 266 267 template <typename T> 268 ProtectedMemory<T>::Initializer::Initializer(ProtectedMemory<T>* PM, 269 const T& Init) { 270 AutoWritableMemory writer = AutoWritableMemory::Create(*PM); 271 **PM = Init; 272 } 273 274 } // namespace base 275 276 #endif // BASE_MEMORY_PROTECTED_MEMORY_H_ 277