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