// Copyright 2024 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/gwp_asan/client/extreme_lightweight_detector_malloc_shims.h" #include <atomic> #include "base/compiler_specific.h" #include "base/functional/bind.h" #include "base/no_destructor.h" #include "base/trace_event/malloc_dump_provider.h" #include "components/gwp_asan/client/sampling_state.h" #include "components/gwp_asan/common/extreme_lightweight_detector_util.h" #include "partition_alloc/lightweight_quarantine.h" #include "partition_alloc/partition_address_space.h" #include "partition_alloc/partition_root.h" #include "partition_alloc/shim/allocator_shim.h" #include "partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h" namespace gwp_asan::internal { namespace { AllocatorDispatch; extern AllocatorDispatch allocator_dispatch; // By being implemented as a global with inline method definitions, method calls // and member accesses are inlined and as efficient as possible in the // performance-sensitive allocation hot-path. // // Note that this optimization has not been benchmarked. However since it is // easy to do there is no reason to pay the extra cost. SamplingState<EXTREMELIGHTWEIGHTDETECTOR> sampling_state; LightweightQuarantineBranch; LightweightQuarantineBranchConfig; LightweightQuarantineRoot; ExtremeLightweightDetectorOptions init_options; std::atomic<bool> is_quarantine_initialized = …; // The PartitionRoot used by the PartitionAlloc-Everywhere (i.e. PartitionAlloc // as malloc), which is also the target partition root of the quarantine. // Since LightweightQuarantineRoot is designed to be used for a certain // PartitionRoot and LightweightQuarantineBranch::Quarantine() cannot handle // an object in an unknown root, the Extreme LUD performs only for the objects // in this PartitionRoot. partition_alloc::PartitionRoot* lightweight_quarantine_partition_root; // A raw pointer to the LightweightQuarantineBranch as the fast path to the // object. This bypasses the access check and indirect access due to the // following std::optional and base::NoDestructor. LightweightQuarantineBranch* lightweight_quarantine_branch; // The memory storage for the quarantine root and branch to make them alive for // the process lifetime. std::optional reserves the memory space without // constructing the objects and allows to construct them lazily. std::optional<LightweightQuarantineRoot> lightweight_quarantine_root_storage; std::optional<base::NoDestructor<LightweightQuarantineBranch>> lightweight_quarantine_branch_storage; // Sets up all we need and returns true, or returns false. // // We need to wait for the completion of `allocator_shim::ConfigurePartitions` // so that the default PartitionRoot for `malloc` is fixed and the quarantine // will be created for the default PartitionRoot. Until then, returns false. bool TryInitSlow(); inline bool TryInit() { … } bool TryInitSlow() { … } // Quarantines the object pointed to by `object`. // Returns true when the object is quarantined (hence will be freed later) or // freed immediately, otherwise false. // // CAUTION: No deallocation is allowed in this function because it causes // a reentrancy issue. inline bool Quarantine(void* object) { … } void FreeFn(void* address, void* context) { … } void FreeDefiniteSizeFn(void* address, size_t size, void* context) { … } AllocatorDispatch allocator_dispatch = …; [[maybe_unused]] base::trace_event::MallocDumpProvider::ExtremeLUDStats GetStats() { … } } // namespace void InstallExtremeLightweightDetectorHooks( const ExtremeLightweightDetectorOptions& options) { … } partition_alloc::internal::LightweightQuarantineBranch& GetEludQuarantineBranchForTesting() { … } } // namespace gwp_asan::internal