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/pointers/raw_ptr_backup_ref_impl.h"
6 
7 #include <cstdint>
8 
9 #include "partition_alloc/dangling_raw_ptr_checks.h"
10 #include "partition_alloc/in_slot_metadata.h"
11 #include "partition_alloc/partition_alloc.h"
12 #include "partition_alloc/partition_alloc_base/check.h"
13 #include "partition_alloc/partition_alloc_buildflags.h"
14 #include "partition_alloc/partition_root.h"
15 #include "partition_alloc/reservation_offset_table.h"
16 
17 namespace base::internal {
18 
19 template <bool AllowDangling, bool DisableBRP>
AcquireInternal(uintptr_t address)20 void RawPtrBackupRefImpl<AllowDangling, DisableBRP>::AcquireInternal(
21     uintptr_t address) {
22 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
23   PA_BASE_CHECK(UseBrp(address));
24 #endif
25   auto [slot_start, slot_size] =
26       partition_alloc::PartitionAllocGetSlotStartAndSizeInBRPPool(address);
27   if constexpr (AllowDangling) {
28     partition_alloc::PartitionRoot::InSlotMetadataPointerFromSlotStartAndSize(
29         slot_start, slot_size)
30         ->AcquireFromUnprotectedPtr();
31   } else {
32     partition_alloc::PartitionRoot::InSlotMetadataPointerFromSlotStartAndSize(
33         slot_start, slot_size)
34         ->Acquire();
35   }
36 }
37 
38 template <bool AllowDangling, bool DisableBRP>
ReleaseInternal(uintptr_t address)39 void RawPtrBackupRefImpl<AllowDangling, DisableBRP>::ReleaseInternal(
40     uintptr_t address) {
41 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
42   PA_BASE_CHECK(UseBrp(address));
43 #endif
44   auto [slot_start, slot_size] =
45       partition_alloc::PartitionAllocGetSlotStartAndSizeInBRPPool(address);
46   if constexpr (AllowDangling) {
47     if (partition_alloc::PartitionRoot::
48             InSlotMetadataPointerFromSlotStartAndSize(slot_start, slot_size)
49                 ->ReleaseFromUnprotectedPtr()) {
50       partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
51     }
52   } else {
53     if (partition_alloc::PartitionRoot::
54             InSlotMetadataPointerFromSlotStartAndSize(slot_start, slot_size)
55                 ->Release()) {
56       partition_alloc::internal::PartitionAllocFreeForRefCounting(slot_start);
57     }
58   }
59 }
60 
61 template <bool AllowDangling, bool DisableBRP>
ReportIfDanglingInternal(uintptr_t address)62 void RawPtrBackupRefImpl<AllowDangling, DisableBRP>::ReportIfDanglingInternal(
63     uintptr_t address) {
64   if (partition_alloc::internal::IsUnretainedDanglingRawPtrCheckEnabled()) {
65     if (IsSupportedAndNotNull(address)) {
66       auto [slot_start, slot_size] =
67           partition_alloc::PartitionAllocGetSlotStartAndSizeInBRPPool(address);
68       partition_alloc::PartitionRoot::InSlotMetadataPointerFromSlotStartAndSize(
69           slot_start, slot_size)
70           ->ReportIfDangling();
71     }
72   }
73 }
74 
75 // static
76 template <bool AllowDangling, bool DisableBRP>
77 bool RawPtrBackupRefImpl<AllowDangling, DisableBRP>::
CheckPointerWithinSameAlloc(uintptr_t before_addr,uintptr_t after_addr,size_t type_size)78     CheckPointerWithinSameAlloc(uintptr_t before_addr,
79                                 uintptr_t after_addr,
80                                 size_t type_size) {
81   partition_alloc::internal::PtrPosWithinAlloc ptr_pos_within_alloc =
82       partition_alloc::internal::IsPtrWithinSameAlloc(before_addr, after_addr,
83                                                       type_size);
84   // No need to check that |new_ptr| is in the same pool, as
85   // IsPtrWithinSameAlloc() checks that it's within the same allocation, so
86   // must be the same pool.
87   PA_BASE_CHECK(ptr_pos_within_alloc !=
88                 partition_alloc::internal::PtrPosWithinAlloc::kFarOOB);
89 
90 #if BUILDFLAG(BACKUP_REF_PTR_POISON_OOB_PTR)
91   return ptr_pos_within_alloc ==
92          partition_alloc::internal::PtrPosWithinAlloc::kAllocEnd;
93 #else
94   return false;
95 #endif
96 }
97 
98 template <bool AllowDangling, bool DisableBRP>
IsPointeeAlive(uintptr_t address)99 bool RawPtrBackupRefImpl<AllowDangling, DisableBRP>::IsPointeeAlive(
100     uintptr_t address) {
101 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
102   PA_BASE_CHECK(UseBrp(address));
103 #endif
104   auto [slot_start, slot_size] =
105       partition_alloc::PartitionAllocGetSlotStartAndSizeInBRPPool(address);
106   return partition_alloc::PartitionRoot::
107       InSlotMetadataPointerFromSlotStartAndSize(slot_start, slot_size)
108           ->IsAlive();
109 }
110 
111 // Explicitly instantiates the two BackupRefPtr variants in the .cc. This
112 // ensures the definitions not visible from the .h are available in the binary.
113 template struct RawPtrBackupRefImpl</*AllowDangling=*/false,
114                                     /*DisableBRP=*/false>;
115 template struct RawPtrBackupRefImpl</*AllowDangling=*/false,
116                                     /*DisableBRP=*/true>;
117 template struct RawPtrBackupRefImpl</*AllowDangling=*/true,
118                                     /*DisableBRP=*/false>;
119 template struct RawPtrBackupRefImpl</*AllowDangling=*/true,
120                                     /*DisableBRP=*/true>;
121 
122 #if BUILDFLAG(PA_DCHECK_IS_ON) || BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
CheckThatAddressIsntWithinFirstPartitionPage(uintptr_t address)123 void CheckThatAddressIsntWithinFirstPartitionPage(uintptr_t address) {
124   if (partition_alloc::internal::IsManagedByDirectMap(address)) {
125     uintptr_t reservation_start =
126         partition_alloc::internal::GetDirectMapReservationStart(address);
127     PA_BASE_CHECK(address - reservation_start >=
128                   partition_alloc::PartitionPageSize());
129   } else {
130     PA_BASE_CHECK(partition_alloc::internal::IsManagedByNormalBuckets(address));
131     PA_BASE_CHECK(address % partition_alloc::kSuperPageSize >=
132                   partition_alloc::PartitionPageSize());
133   }
134 }
135 #endif  // BUILDFLAG(PA_DCHECK_IS_ON) ||
136         // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SLOW_CHECKS)
137 
138 }  // namespace base::internal
139