blob: e6291ceace4b575325f1436323adf39b754cbd90 [file] [log] [blame]
Jeff Goura3e4ebd2024-01-23 21:04:491// 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
danakj51d26a42024-04-25 14:23:565#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
Jeff Goura3e4ebd2024-01-23 21:04:4910// Protected memory is memory holding security-sensitive data intended to be
11// left read-only for the majority of its lifetime to avoid being overwritten
12// by attackers. ProtectedMemory is a simple wrapper around platform-specific
13// APIs to set memory read-write and read-only when required. Protected memory
14// should be set read-write for the minimum amount of time required.
15//
16// Normally mutable variables are held in read-write memory and constant data
17// is held in read-only memory to ensure it is not accidentally overwritten.
18// In some cases we want to hold mutable variables in read-only memory, except
19// when they are being written to, to ensure that they are not tampered with.
20//
21// ProtectedMemory is a container class intended to hold a single variable in
22// read-only memory, except when explicitly set read-write. The variable can be
André Kempe0f7da88a2024-03-22 19:12:4723// set read-write by creating a scoped AutoWritableMemory object, the memory
24// stays writable until the returned object goes out of scope and is destructed.
25// The wrapped variable can be accessed using operator* and operator->.
Jeff Goura3e4ebd2024-01-23 21:04:4926//
André Kempe0f7da88a2024-03-22 19:12:4727// Instances of ProtectedMemory must be defined using DEFINE_PROTECTED_DATA
28// and as global variables. Global definitions are required to avoid the linker
29// placing statics in inlinable functions into a comdat section and setting the
30// protected memory section read-write when they are merged. If a declaration of
31// a protected variable is required DECLARE_PROTECTED_DATA should be used.
32//
33// Instances of `base::ProtectedMemory` use constant initialization. To allow
34// protection of objects which do not provide constant initialization or would
35// require a global constructor, `base::ProtectedMemory` provides lazy
Jeffrey Goure63ec7f2024-08-28 01:12:5336// initialization through `ProtectedMemoryInitializer`. Additionally, on
37// platforms where it is not possible to have the protected memory section start
38// as read-only, the very first call to ProtectedMemoryInitializer will
39// initialize the memory section to read-only. Explicit initialization through
40// `ProtectedMemoryInitializer` is mandatory, even for objects that provide
41// constant initialization. This ensures that in the unlikely event that the
42// value is modified before the memory is initialized to read-only, it will be
43// forced back to a known, safe, initial state before it ever used. If data is
44// accessed without initialization a CHECK triggers. This CHECK is not expected
45// to provided security guarantees, but to help catch programming errors.
46//
47// TODO(crbug.com/356428974): Improve protection offered by Protected Memory.
André Kempe0f7da88a2024-03-22 19:12:4748//
49// `base::ProtectedMemory` requires T to be trivially destructible. T having
50// a non-trivial constructor indicates that is holds data which can not be
51// protected by `base::ProtectedMemory`.
Jeff Goura3e4ebd2024-01-23 21:04:4952//
53// EXAMPLE:
54//
55// struct Items { void* item1; };
Jeffrey Goure63ec7f2024-08-28 01:12:5356// static DEFINE_PROTECTED_DATA base::ProtectedMemory<Items> items;
Jeff Goura3e4ebd2024-01-23 21:04:4957// void InitializeItems() {
58// // Explicitly set items read-write before writing to it.
André Kempe0f7da88a2024-03-22 19:12:4759// auto writer = base::AutoWritableMemory(items);
60// writer->item1 = /* ... */;
Jeff Goura3e4ebd2024-01-23 21:04:4961// assert(items->item1 != nullptr);
62// // items is set back to read-only on the destruction of writer
63// }
64//
65// using FnPtr = void (*)(void);
Jeffrey Goure63ec7f2024-08-28 01:12:5366// DEFINE_PROTECTED_DATA base::ProtectedMemory<FnPtr> fnPtr;
Jeff Goura3e4ebd2024-01-23 21:04:4967// FnPtr ResolveFnPtr(void) {
André Kempe0f7da88a2024-03-22 19:12:4768// // `ProtectedMemoryInitializer` is a helper class for creating a static
Jeff Goura3e4ebd2024-01-23 21:04:4969// // initializer for a ProtectedMemory variable. It implicitly sets the
70// // variable read-write during initialization.
André Kempe0f7da88a2024-03-22 19:12:4771// static base::ProtectedMemoryInitializer initializer(&fnPtr,
Jeff Goura3e4ebd2024-01-23 21:04:4972// reinterpret_cast<FnPtr>(dlsym(/* ... */)));
73// return *fnPtr;
74// }
75
76#ifndef BASE_MEMORY_PROTECTED_MEMORY_H_
77#define BASE_MEMORY_PROTECTED_MEMORY_H_
78
André Kempe5adc4d5a2024-03-15 12:23:3379#include <stddef.h>
80#include <stdint.h>
81
82#include <memory>
André Kempe0f7da88a2024-03-22 19:12:4783#include <type_traits>
André Kempe5adc4d5a2024-03-15 12:23:3384
Jeffrey Goure63ec7f2024-08-28 01:12:5385#include "base/bits.h"
André Kempe5adc4d5a2024-03-15 12:23:3386#include "base/check.h"
Jeff Goura3e4ebd2024-01-23 21:04:4987#include "base/check_op.h"
Tom Sepez04e98bf2024-10-25 18:19:3188#include "base/compiler_specific.h"
André Kempe5adc4d5a2024-03-15 12:23:3389#include "base/gtest_prod_util.h"
Jeffrey Goure63ec7f2024-08-28 01:12:5390#include "base/memory/page_size.h"
Jeff Goura3e4ebd2024-01-23 21:04:4991#include "base/memory/protected_memory_buildflags.h"
92#include "base/memory/raw_ref.h"
93#include "base/no_destructor.h"
94#include "base/synchronization/lock.h"
André Kempe5adc4d5a2024-03-15 12:23:3395#include "base/thread_annotations.h"
Jeff Goura3e4ebd2024-01-23 21:04:4996#include "build/build_config.h"
97
98#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
99#if BUILDFLAG(IS_WIN)
100// Define a read-write prot section. The $a, $mem, and $z 'sub-sections' are
101// merged alphabetically so $a and $z are used to define the start and end of
102// the protected memory section, and $mem holds protected variables.
103// (Note: Sections in Portable Executables are equivalent to segments in other
104// executable formats, so this section is mapped into its own pages.)
105#pragma section("prot$a", read, write)
106#pragma section("prot$mem", read, write)
107#pragma section("prot$z", read, write)
108
109// We want the protected memory section to be read-only, not read-write so we
110// instruct the linker to set the section read-only at link time. We do this
111// at link time instead of compile time, because defining the prot section
112// read-only would cause mis-compiles due to optimizations assuming that the
113// section contents are constant.
114#pragma comment(linker, "/SECTION:prot,R")
115
116__declspec(allocate("prot$a"))
117__declspec(selectany) char __start_protected_memory;
118__declspec(allocate("prot$z"))
119__declspec(selectany) char __stop_protected_memory;
120
André Kempe0f7da88a2024-03-22 19:12:47121#define DECLARE_PROTECTED_DATA constinit
122#define DEFINE_PROTECTED_DATA constinit __declspec(allocate("prot$mem"))
Jeffrey Goure63ec7f2024-08-28 01:12:53123#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
124// This value is used to align the writers variable. That variable needs to be
125// aligned to ensure that the protected memory section starts on a page
126// boundary.
127#if (PA_BUILDFLAG(IS_ANDROID) && PA_BUILDFLAG(PA_ARCH_CPU_64_BITS)) || \
128 (PA_BUILDFLAG(IS_LINUX) && PA_BUILDFLAG(PA_ARCH_CPU_ARM64))
129// arm64 supports 4kb, 16kb, and 64kb pages. Set to the largest of 64kb as that
130// will guarantee the section is page aligned regardless of the choice.
131inline constexpr int kProtectedMemoryAlignment = 65536;
132#elif PA_BUILDFLAG(PA_ARCH_CPU_PPC64) || defined(ARCH_CPU_PPC64)
133// Modern ppc64 systems support 4kB (shift = 12) and 64kB (shift = 16) page
134// sizes. Set to the largest of 64kb as that will guarantee the section is page
135// aligned regardless of the choice.
136inline constexpr int kProtectedMemoryAlignment = 65536;
137#elif defined(_MIPS_ARCH_LOONGSON) || PA_BUILDFLAG(PA_ARCH_CPU_LOONGARCH64) || \
138 defined(ARCH_CPU_LOONGARCH64)
139// 16kb page size
140inline constexpr int kProtectedMemoryAlignment = 16384;
Jeff Goura3e4ebd2024-01-23 21:04:49141#else
Jeffrey Goure63ec7f2024-08-28 01:12:53142// 4kb page size
143inline constexpr int kProtectedMemoryAlignment = 4096;
144#endif
145
146__asm__(".section protected_memory, \"a\"\n\t");
147__asm__(".section protected_memory_buffer, \"a\"\n\t");
148
149// Explicitly mark these variables hidden so the symbols are local to the
150// currently built component. Otherwise they are created with global (external)
151// linkage and component builds would break because a single pair of these
152// symbols would override the rest.
153__attribute__((visibility("hidden"))) extern char __start_protected_memory;
154__attribute__((visibility("hidden"))) extern char __stop_protected_memory;
155
156#define DECLARE_PROTECTED_DATA constinit
157#define DEFINE_PROTECTED_DATA \
158 constinit __attribute__((section("protected_memory")))
159#elif BUILDFLAG(IS_MAC)
160// The segment the section is in is defined with a linker flag in
161// build/config/mac/BUILD.gn
162#define DECLARE_PROTECTED_DATA constinit
163#define DEFINE_PROTECTED_DATA \
164 constinit __attribute__((section("PROTECTED_MEMORY, protected_memory")))
165
166extern char __start_protected_memory __asm(
167 "section$start$PROTECTED_MEMORY$protected_memory");
168extern char __stop_protected_memory __asm(
169 "section$end$PROTECTED_MEMORY$protected_memory");
170#else
171#error "Protected Memory is not supported on this platform."
Jeffrey Gour6f946aad2024-07-11 16:07:54172#endif
Jeff Goura3e4ebd2024-01-23 21:04:49173
174#else
André Kempe0f7da88a2024-03-22 19:12:47175#define DECLARE_PROTECTED_DATA constinit
176#define DEFINE_PROTECTED_DATA DECLARE_PROTECTED_DATA
Jeff Goura3e4ebd2024-01-23 21:04:49177#endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
178
179namespace base {
180
Jeffrey Gour6f946aad2024-07-11 16:07:54181template <typename T>
Jeff Goura3e4ebd2024-01-23 21:04:49182class AutoWritableMemory;
183
André Kempe5adc4d5a2024-03-15 12:23:33184FORWARD_DECLARE_TEST(ProtectedMemoryDeathTest, VerifyTerminationOnAccess);
185
André Kempe0f7da88a2024-03-22 19:12:47186namespace internal {
Jeffrey Gour6f946aad2024-07-11 16:07:54187// Helper class which store the data and implement and initialization for
188// constructing the underlying protected data lazily. The instance of T is only
189// constructed when emplace is called.
Will Harrisca5caf822024-07-09 17:47:44190template <typename T>
Jeffrey Gour6f946aad2024-07-11 16:07:54191class ProtectedDataHolder {
Will Harrisca5caf822024-07-09 17:47:44192 public:
193 consteval ProtectedDataHolder() = default;
194
Tom Sepez04e98bf2024-10-25 18:19:31195 T& GetReference() LIFETIME_BOUND { return *GetPointer(); }
196 const T& GetReference() const LIFETIME_BOUND { return *GetPointer(); }
André Kempe0f7da88a2024-03-22 19:12:47197
198 T* GetPointer() {
199 CHECK(constructed_);
200 return reinterpret_cast<T*>(&data_);
201 }
202 const T* GetPointer() const {
203 CHECK(constructed_);
204 return reinterpret_cast<const T*>(&data_);
205 }
206
207 template <typename... U>
208 void emplace(U&&... args) {
209 if (constructed_) {
210 std::destroy_at(reinterpret_cast<T*>(&data_));
211 constructed_ = false;
212 }
213
214 std::construct_at(reinterpret_cast<T*>(&data_), std::forward<U>(args)...);
215 constructed_ = true;
216 }
217
218 private:
219 // Initializing with a constant/zero value ensures no global constructor is
220 // required when instantiating `ProtectedDataHolder` and `ProtectedMemory`.
Arthur Sonzogni299864be12024-12-04 16:52:02221 alignas(T) uint8_t data_[sizeof(T)] = {};
André Kempe0f7da88a2024-03-22 19:12:47222 bool constructed_ = false;
223};
224
225} // namespace internal
226
227// The wrapper class for data of type `T` which is to be stored in protected
228// memory. `ProtectedMemory` provides improved type safety in conjunction with
229// the other classes, although the basic mechanisms like unlocking and
230// re-locking of the memory would also work without it.
231//
232// To allow using `T`s which do not have constant initialization, the template
233// parameter `ConstructLazily` enables a lazy initialization. In this case, an
234// initialization before first access is mandatory (see
235// `ProtectedMemoryInitializer`).
Jeffrey Gour6f946aad2024-07-11 16:07:54236template <typename T>
Jeff Goura3e4ebd2024-01-23 21:04:49237class ProtectedMemory {
238 public:
André Kempe0f7da88a2024-03-22 19:12:47239 // T must be trivially destructible. Otherwise it indicates that T holds data
240 // which would not be covered by this write protection, i.e. data allocated on
André Kempe2e18b292024-04-08 13:56:02241 // heap. This check complements the verification in the constructor since
242 // `ProtectedMemory` with `ConstructLazily` set to `true` is always trivially
243 // destructible.
André Kempe0f7da88a2024-03-22 19:12:47244 static_assert(std::is_trivially_destructible_v<T>);
245
246 // For lazily constructed data we enable this constructor only if there are
247 // no arguments. For lazily constructed data no arguments are accepted as T is
248 // not initialized when `ProtectedMemory<T>` is created but through
249 // `ProtectedMemoryInitializer` instead.
Jeffrey Gour6f946aad2024-07-11 16:07:54250 consteval explicit ProtectedMemory() : data_() {
André Kempe0f7da88a2024-03-22 19:12:47251 static_assert(std::is_trivially_destructible_v<ProtectedMemory>);
252 }
253
Jeff Goura3e4ebd2024-01-23 21:04:49254 ProtectedMemory(const ProtectedMemory&) = delete;
255 ProtectedMemory& operator=(const ProtectedMemory&) = delete;
256
257 // Expose direct access to the encapsulated variable
André Kempe0f7da88a2024-03-22 19:12:47258 const T& operator*() const { return data_.GetReference(); }
259 const T* operator->() const { return data_.GetPointer(); }
Jeff Goura3e4ebd2024-01-23 21:04:49260
261 private:
Jeffrey Gour6f946aad2024-07-11 16:07:54262 friend class AutoWritableMemory<T>;
André Kempe5adc4d5a2024-03-15 12:23:33263 FRIEND_TEST_ALL_PREFIXES(ProtectedMemoryDeathTest, VerifyTerminationOnAccess);
264
Jeffrey Gour6f946aad2024-07-11 16:07:54265 internal::ProtectedDataHolder<T> data_;
Jeff Goura3e4ebd2024-01-23 21:04:49266};
267
Jeff Goura3e4ebd2024-01-23 21:04:49268#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
André Kempe5adc4d5a2024-03-15 12:23:33269namespace internal {
270// Checks that the byte at `ptr` is read-only.
Jeffrey Goure63ec7f2024-08-28 01:12:53271BASE_EXPORT void CheckMemoryReadOnly(const void* ptr);
Jeff Goura3e4ebd2024-01-23 21:04:49272
273// Abstract out platform-specific methods to get the beginning and end of the
274// PROTECTED_MEMORY_SECTION. ProtectedMemoryEnd returns a pointer to the byte
275// past the end of the PROTECTED_MEMORY_SECTION.
André Kempe5adc4d5a2024-03-15 12:23:33276inline constexpr void* kProtectedMemoryStart = &__start_protected_memory;
277inline constexpr void* kProtectedMemoryEnd = &__stop_protected_memory;
278} // namespace internal
Jeff Goura3e4ebd2024-01-23 21:04:49279#endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
280
André Kempe5adc4d5a2024-03-15 12:23:33281// Provide some common functionality for `AutoWritableMemory<T>`.
282class BASE_EXPORT AutoWritableMemoryBase {
283 protected:
284#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
285 // Checks that `object` is located within the interval
286 // (internal::kProtectedMemoryStart, internal::kProtectedMemoryEnd).
287 template <typename T>
288 static bool IsObjectInProtectedSection(const T& object) {
289 const T* const ptr = std::addressof(object);
290 const T* const ptr_end = ptr + 1;
Jeffrey Gour6f946aad2024-07-11 16:07:54291 return (ptr >= internal::kProtectedMemoryStart) &&
André Kempe5adc4d5a2024-03-15 12:23:33292 (ptr_end <= internal::kProtectedMemoryEnd);
293 }
294
295 template <typename T>
Jeffrey Goure63ec7f2024-08-28 01:12:53296 static void CheckObjectReadOnly(const T& object) {
297 internal::CheckMemoryReadOnly(std::addressof(object));
André Kempe5adc4d5a2024-03-15 12:23:33298 }
299
300 template <typename T>
301 static bool SetObjectReadWrite(T& object) {
302 T* const ptr = std::addressof(object);
303 T* const ptr_end = ptr + 1;
304 return SetMemoryReadWrite(ptr, ptr_end);
305 }
306
307 static bool SetProtectedSectionReadOnly() {
308 return SetMemoryReadOnly(internal::kProtectedMemoryStart,
309 internal::kProtectedMemoryEnd);
310 }
311
Jeffrey Goure63ec7f2024-08-28 01:12:53312 static bool IsSectionStartPageAligned() {
313 const uintptr_t protected_memory_start =
314 reinterpret_cast<uintptr_t>(internal::kProtectedMemoryStart);
315 const uintptr_t page_start =
316 bits::AlignDown(protected_memory_start, GetPageSize());
317 return page_start == protected_memory_start;
318 }
319
André Kempe5adc4d5a2024-03-15 12:23:33320 // When linking, each DSO will have its own protected section. We can't keep
321 // track of each section, yet we have to ensure to always unlock and re-lock
322 // the correct section.
323 //
324 // We solve this by defining a separate global writers variable (explained
325 // below) in every dynamic shared object (DSO) that includes this header. To
326 // do that we use this structure to define global writer data without
327 // duplicate symbol errors.
328 //
329 // Storing the data in a substructure is required to store `writers` within
330 // the protected subsection. If `writers` and `writers_lock()` are located
331 // directly in `AutoWritableMemoryBase`, for unknown reasons `writers` is not
332 // placed into the protected section.
333 struct WriterData {
334 // `writers` is a global holding the number of ProtectedMemory instances set
335 // writable, used to avoid races setting protected memory readable/writable.
336 // When this reaches zero the protected memory region is set read only.
337 // Access is controlled by writers_lock.
338 //
339 // Declare writers in the protected memory section to avoid the scenario
340 // where an attacker could overwrite it with a large value and invoke code
341 // that constructs and destructs an AutoWritableMemory. After such a call
342 // protected memory would still be set writable because writers > 0.
Jeffrey Goure63ec7f2024-08-28 01:12:53343#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
344 // On Linux, the protected memory section is not automatically page aligned.
345 // This means that attempts to reset the protected memory region to readonly
346 // will set some of the preceding section that is on the same page readonly
347 // as well. By forcing the writers to be aligned on a multiple of the page
348 // size, we can ensure the protected memory section starts on a page
349 // boundary, preventing this issue.
350 constinit __attribute__((section("protected_memory"),
351 aligned(kProtectedMemoryAlignment)))
352#else
André Kempe0f7da88a2024-03-22 19:12:47353 DEFINE_PROTECTED_DATA
Jeffrey Goure63ec7f2024-08-28 01:12:53354#endif
André Kempe5adc4d5a2024-03-15 12:23:33355 static inline size_t writers GUARDED_BY(writers_lock()) = 0;
356
Jeffrey Goure63ec7f2024-08-28 01:12:53357#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
358 // On Linux, there is no guarantee the section following the protected
359 // memory section is page aligned. This can result in attempts to change
360 // the access permissions of the end of the protected memory section
361 // overflowing to the next section. To ensure this doesn't happen, a buffer
362 // section called protected_memory_buffer is created. Since the very first
363 // variable declared after writers is put in this section, it will be
364 // created as the next section after the protected memory section (since
365 // sections are created in the order they are declared in the source file).
366 // By explicitly setting the alignment of the variable to a multiple of the
367 // page size, we can ensure this buffer section starts on a page boundary.
368 // This guarantees that altering the access permissions of the end of the
369 // protected memory section will not affect the next section. The variable
370 // protected_memory_section_buffer serves no purpose other than to ensure
371 // protected_memory_buffer section is created.
372 constinit
373 __attribute__((section("protected_memory_buffer"),
374 aligned(kProtectedMemoryAlignment))) static inline bool
375 protected_memory_section_buffer = false;
376#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
377
André Kempe5adc4d5a2024-03-15 12:23:33378 // Synchronizes access to the writers variable and the simultaneous actions
379 // that need to happen alongside writers changes, e.g. setting the protected
380 // memory region readable when writers is decremented to 0.
381 static Lock& writers_lock() {
382 static NoDestructor<Lock> writers_lock;
383 return *writers_lock;
384 }
385 };
386
387 private:
388 // Abstract out platform-specific memory APIs. |end| points to the byte
389 // past the end of the region of memory having its memory protections
390 // changed.
391 static bool SetMemoryReadWrite(void* start, void* end);
392 static bool SetMemoryReadOnly(void* start, void* end);
393#endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
Jeff Goura3e4ebd2024-01-23 21:04:49394};
Jeff Goura3e4ebd2024-01-23 21:04:49395
Jeffrey Goure63ec7f2024-08-28 01:12:53396#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
397// This class acts as a static initializer that initializes the protected memory
398// region to read only. It will be engaged the first time a protected memory
399// object is statically initialized.
400class BASE_EXPORT AutoWritableMemoryInitializer
401 : public AutoWritableMemoryBase {
402 public:
403#if BUILDFLAG(IS_WIN)
404 AutoWritableMemoryInitializer() { CHECK(IsSectionStartPageAligned()); }
405#else
406 AutoWritableMemoryInitializer() LOCKS_EXCLUDED(WriterData::writers_lock()) {
407 CHECK(IsSectionStartPageAligned());
408 // This doesn't need to be run on Windows, because the linker can pre-set
409 // the memory to read-only.
410 AutoLock auto_lock(WriterData::writers_lock());
411 // Reset the writers variable to 0 to ensure that the attacker didn't set
412 // the variable to something large before the section was read-only.
413 WriterData::writers = 0;
414 CHECK(SetProtectedSectionReadOnly());
415#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
416 // Set the protected_memory_section_buffer to true to ensure the buffer
417 // section is created. If a variable is declared but not used the memory
418 // section won't be created.
419 WriterData::protected_memory_section_buffer = true;
420#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID)
421 }
422#endif // BUILDFLAG(IS_WIN)
423};
424#endif // BUILDFLAG(PROTECTED_MEMORY_ENABLED)
425
Jeff Goura3e4ebd2024-01-23 21:04:49426// A class that sets a given ProtectedMemory variable writable while the
427// AutoWritableMemory is in scope. This class implements the logic for setting
428// the protected memory region read-only/read-write in a thread-safe manner.
André Kempe5adc4d5a2024-03-15 12:23:33429//
430// |AutoWritableMemory| affects the write-permissions of _all_ protected data
431// for a DSO, not just of the instance that it's being passed! All protected
432// data is stored within the same binary section. At the same time, the OS-level
433// support enforcing write protection can only be changed at page level. To
434// allow a more fine grained control a dedicated page per instance of protected
435// data would be required.
Jeffrey Gour6f946aad2024-07-11 16:07:54436template <typename T>
André Kempe5adc4d5a2024-03-15 12:23:33437class AutoWritableMemory : public AutoWritableMemoryBase {
Jeff Goura3e4ebd2024-01-23 21:04:49438 public:
Jeffrey Gour6f946aad2024-07-11 16:07:54439 explicit AutoWritableMemory(ProtectedMemory<T>& protected_memory)
André Kempe5adc4d5a2024-03-15 12:23:33440#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
441 LOCKS_EXCLUDED(WriterData::writers_lock())
442#endif
Jeff Goura3e4ebd2024-01-23 21:04:49443 : protected_memory_(protected_memory) {
444#if BUILDFLAG(PROTECTED_MEMORY_ENABLED)
André Kempe5adc4d5a2024-03-15 12:23:33445
446 // Check that the data is located in the protected section to
447 // ensure consistency of data.
448 CHECK(IsObjectInProtectedSection(protected_memory_->data_));
449 CHECK(IsObjectInProtectedSection(WriterData::writers));
Jeff Goura3e4ebd2024-01-23 21:04:49450
451 {
Jeffrey Goure63ec7f2024-08-28 01:12:53452 AutoLock auto_lock(WriterData::writers_lock());
André Kempe5adc4d5a2024-03-15 12:23:33453
454 if (WriterData::writers == 0) {
Jeffrey Gour