• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 "base/memory/nonscannable_memory.h"
6 
7 #include <stdlib.h>
8 
9 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
10 #include "base/feature_list.h"
11 #include "base/no_destructor.h"
12 
13 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
14 #include "base/allocator/partition_alloc_features.h"
15 #include "base/allocator/partition_allocator/shim/allocator_shim_default_dispatch_to_partition_alloc.h"
16 
17 #if BUILDFLAG(USE_STARSCAN)
18 #include "base/allocator/partition_allocator/starscan/metadata_allocator.h"
19 #include "base/allocator/partition_allocator/starscan/pcscan.h"
20 #endif
21 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
22 
23 namespace base {
24 namespace internal {
25 
26 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
27 template <bool Quarantinable>
28 NonScannableAllocatorImpl<Quarantinable>::NonScannableAllocatorImpl() = default;
29 template <bool Quarantinable>
30 NonScannableAllocatorImpl<Quarantinable>::~NonScannableAllocatorImpl() =
31     default;
32 
33 template <bool Quarantinable>
34 NonScannableAllocatorImpl<Quarantinable>&
Instance()35 NonScannableAllocatorImpl<Quarantinable>::Instance() {
36   static base::NoDestructor<NonScannableAllocatorImpl> instance;
37   return *instance;
38 }
39 
40 template <bool Quarantinable>
Alloc(size_t size)41 void* NonScannableAllocatorImpl<Quarantinable>::Alloc(size_t size) {
42 #if BUILDFLAG(USE_STARSCAN)
43   // TODO(bikineev): Change to LIKELY once PCScan is enabled by default.
44   if (UNLIKELY(pcscan_enabled_.load(std::memory_order_acquire))) {
45     PA_DCHECK(allocator_.get());
46     return allocator_->root()->AllocWithFlagsNoHooks(
47         0, size, partition_alloc::PartitionPageSize());
48   }
49 #endif  // BUILDFLAG(USE_STARSCAN)
50   // Otherwise, dispatch to default partition.
51   return allocator_shim::internal::PartitionAllocMalloc::Allocator()
52       ->AllocWithFlagsNoHooks(0, size, partition_alloc::PartitionPageSize());
53 }
54 
55 template <bool Quarantinable>
Free(void * ptr)56 void NonScannableAllocatorImpl<Quarantinable>::Free(void* ptr) {
57   partition_alloc::ThreadSafePartitionRoot::FreeNoHooks(ptr);
58 }
59 
60 template <bool Quarantinable>
NotifyPCScanEnabled()61 void NonScannableAllocatorImpl<Quarantinable>::NotifyPCScanEnabled() {
62 #if BUILDFLAG(USE_STARSCAN)
63   allocator_.reset(partition_alloc::internal::MakePCScanMetadata<
64                    partition_alloc::PartitionAllocator>());
65   allocator_->init({
66       partition_alloc::PartitionOptions::AlignedAlloc::kDisallowed,
67       partition_alloc::PartitionOptions::ThreadCache::kDisabled,
68       Quarantinable
69           ? partition_alloc::PartitionOptions::Quarantine::kAllowed
70           : partition_alloc::PartitionOptions::Quarantine::kDisallowed,
71       partition_alloc::PartitionOptions::Cookie::kAllowed,
72       partition_alloc::PartitionOptions::BackupRefPtr::kDisabled,
73       partition_alloc::PartitionOptions::BackupRefPtrZapping::kDisabled,
74       partition_alloc::PartitionOptions::UseConfigurablePool::kNo,
75   });
76   if (Quarantinable) {
77     partition_alloc::internal::PCScan::RegisterNonScannableRoot(
78         allocator_->root());
79   }
80   pcscan_enabled_.store(true, std::memory_order_release);
81 #endif  // BUILDFLAG(USE_STARSCAN)
82 }
83 
84 template class NonScannableAllocatorImpl<true>;
85 template class NonScannableAllocatorImpl<false>;
86 
87 #endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
88 
89 }  // namespace internal
90 
AllocNonScannable(size_t size)91 void* AllocNonScannable(size_t size) {
92 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
93   return internal::NonScannableAllocatorImpl</*Quarantinable=*/true>::Instance()
94       .Alloc(size);
95 #else
96   return ::malloc(size);
97 #endif
98 }
99 
FreeNonScannable(void * ptr)100 void FreeNonScannable(void* ptr) {
101 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
102   internal::NonScannableAllocatorImpl</*Quarantinable=*/true>::Free(ptr);
103 #else
104   return ::free(ptr);
105 #endif
106 }
107 
AllocNonQuarantinable(size_t size)108 void* AllocNonQuarantinable(size_t size) {
109 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
110   return internal::NonScannableAllocatorImpl<
111              /*Quarantinable=*/false>::Instance()
112       .Alloc(size);
113 #else
114   return ::malloc(size);
115 #endif
116 }
117 
FreeNonQuarantinable(void * ptr)118 void FreeNonQuarantinable(void* ptr) {
119 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
120   internal::NonScannableAllocatorImpl</*Quarantinable=*/false>::Free(ptr);
121 #else
122   return ::free(ptr);
123 #endif
124 }
125 
126 }  // namespace base
127