• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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