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