1 // Copyright 2023 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 "partition_alloc/thread_isolation/thread_isolation.h"
6 
7 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
8 
9 #include "partition_alloc/address_pool_manager.h"
10 #include "partition_alloc/page_allocator.h"
11 #include "partition_alloc/partition_alloc_check.h"
12 #include "partition_alloc/partition_alloc_constants.h"
13 #include "partition_alloc/reservation_offset_table.h"
14 
15 #if BUILDFLAG(ENABLE_PKEYS)
16 #include "partition_alloc/thread_isolation/pkey.h"
17 #endif
18 
19 namespace partition_alloc::internal {
20 
21 #if BUILDFLAG(PA_DCHECK_IS_ON)
22 ThreadIsolationSettings ThreadIsolationSettings::settings;
23 #endif
24 
WriteProtectThreadIsolatedMemory(ThreadIsolationOption thread_isolation,void * address,size_t size,bool read_only=false)25 void WriteProtectThreadIsolatedMemory(ThreadIsolationOption thread_isolation,
26                                       void* address,
27                                       size_t size,
28                                       bool read_only = false) {
29   PA_DCHECK((reinterpret_cast<uintptr_t>(address) &
30              PA_THREAD_ISOLATED_ALIGN_OFFSET_MASK) == 0);
31   if (read_only) {
32     SetSystemPagesAccess(
33         address, size,
34         PageAccessibilityConfiguration(
35             thread_isolation.enabled
36                 ? PageAccessibilityConfiguration::Permissions::kRead
37                 : PageAccessibilityConfiguration::Permissions::kReadWrite));
38     return;
39   }
40 #if BUILDFLAG(ENABLE_PKEYS)
41   partition_alloc::internal::TagMemoryWithPkey(
42       thread_isolation.enabled ? thread_isolation.pkey : kDefaultPkey, address,
43       size);
44 #else
45 #error unexpected thread isolation mode
46 #endif
47 }
48 
49 template <typename T>
WriteProtectThreadIsolatedVariable(ThreadIsolationOption thread_isolation,T & var,size_t offset=0,bool read_only=false)50 void WriteProtectThreadIsolatedVariable(ThreadIsolationOption thread_isolation,
51                                         T& var,
52                                         size_t offset = 0,
53                                         bool read_only = false) {
54   WriteProtectThreadIsolatedMemory(thread_isolation, (char*)&var + offset,
55                                    sizeof(T) - offset, read_only);
56 }
57 
MprotectWithThreadIsolation(void * addr,size_t len,int prot,ThreadIsolationOption thread_isolation)58 int MprotectWithThreadIsolation(void* addr,
59                                 size_t len,
60                                 int prot,
61                                 ThreadIsolationOption thread_isolation) {
62 #if BUILDFLAG(ENABLE_PKEYS)
63   return PkeyMprotect(addr, len, prot, thread_isolation.pkey);
64 #endif
65 }
66 
WriteProtectThreadIsolatedGlobals(ThreadIsolationOption thread_isolation)67 void WriteProtectThreadIsolatedGlobals(ThreadIsolationOption thread_isolation) {
68   WriteProtectThreadIsolatedVariable(thread_isolation,
69                                      PartitionAddressSpace::setup_, 0, true);
70 
71   AddressPoolManager::Pool* pool =
72       AddressPoolManager::GetInstance().GetPool(kThreadIsolatedPoolHandle);
73   WriteProtectThreadIsolatedVariable(
74       thread_isolation, *pool,
75       offsetof(AddressPoolManager::Pool, alloc_bitset_));
76 
77   uint16_t* pkey_reservation_offset_table =
78       GetReservationOffsetTable(kThreadIsolatedPoolHandle);
79   WriteProtectThreadIsolatedMemory(
80       thread_isolation, pkey_reservation_offset_table,
81       ReservationOffsetTable::kReservationOffsetTableLength);
82 
83 #if BUILDFLAG(PA_DCHECK_IS_ON)
84   WriteProtectThreadIsolatedVariable(thread_isolation,
85                                      ThreadIsolationSettings::settings);
86 #endif
87 }
88 
UnprotectThreadIsolatedGlobals()89 void UnprotectThreadIsolatedGlobals() {
90   WriteProtectThreadIsolatedGlobals(ThreadIsolationOption(false));
91 }
92 
93 }  // namespace partition_alloc::internal
94 
95 #endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
96