13cab2bb3Spatrick //===-- guarded_pool_allocator.h --------------------------------*- C++ -*-===// 23cab2bb3Spatrick // 33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information. 53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 63cab2bb3Spatrick // 73cab2bb3Spatrick //===----------------------------------------------------------------------===// 83cab2bb3Spatrick 93cab2bb3Spatrick #ifndef GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_ 103cab2bb3Spatrick #define GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_ 113cab2bb3Spatrick 121f9cb04fSpatrick #include "gwp_asan/common.h" 133cab2bb3Spatrick #include "gwp_asan/definitions.h" 143cab2bb3Spatrick #include "gwp_asan/mutex.h" 153cab2bb3Spatrick #include "gwp_asan/options.h" 16d89ec533Spatrick #include "gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.h" // IWYU pragma: keep 17d89ec533Spatrick #include "gwp_asan/platform_specific/guarded_pool_allocator_posix.h" // IWYU pragma: keep 18d89ec533Spatrick #include "gwp_asan/platform_specific/guarded_pool_allocator_tls.h" 193cab2bb3Spatrick 203cab2bb3Spatrick #include <stddef.h> 213cab2bb3Spatrick #include <stdint.h> 22d89ec533Spatrick // IWYU pragma: no_include <__stddef_max_align_t.h> 233cab2bb3Spatrick 243cab2bb3Spatrick namespace gwp_asan { 253cab2bb3Spatrick // This class is the primary implementation of the allocator portion of GWP- 263cab2bb3Spatrick // ASan. It is the sole owner of the pool of sequentially allocated guarded 273cab2bb3Spatrick // slots. It should always be treated as a singleton. 283cab2bb3Spatrick 293cab2bb3Spatrick // Functions in the public interface of this class are thread-compatible until 303cab2bb3Spatrick // init() is called, at which point they become thread-safe (unless specified 313cab2bb3Spatrick // otherwise). 323cab2bb3Spatrick class GuardedPoolAllocator { 333cab2bb3Spatrick public: 341f9cb04fSpatrick // Name of the GWP-ASan mapping that for `Metadata`. 351f9cb04fSpatrick static constexpr const char *kGwpAsanMetadataName = "GWP-ASan Metadata"; 363cab2bb3Spatrick 373cab2bb3Spatrick // During program startup, we must ensure that memory allocations do not land 383cab2bb3Spatrick // in this allocation pool if the allocator decides to runtime-disable 393cab2bb3Spatrick // GWP-ASan. The constructor value-initialises the class such that if no 403cab2bb3Spatrick // further initialisation takes place, calls to shouldSample() and 413cab2bb3Spatrick // pointerIsMine() will return false. GuardedPoolAllocator()42d89ec533Spatrick constexpr GuardedPoolAllocator() {} 433cab2bb3Spatrick GuardedPoolAllocator(const GuardedPoolAllocator &) = delete; 443cab2bb3Spatrick GuardedPoolAllocator &operator=(const GuardedPoolAllocator &) = delete; 453cab2bb3Spatrick 463cab2bb3Spatrick // Note: This class is expected to be a singleton for the lifetime of the 473cab2bb3Spatrick // program. If this object is initialised, it will leak the guarded page pool 483cab2bb3Spatrick // and metadata allocations during destruction. We can't clean up these areas 493cab2bb3Spatrick // as this may cause a use-after-free on shutdown. 503cab2bb3Spatrick ~GuardedPoolAllocator() = default; 513cab2bb3Spatrick 523cab2bb3Spatrick // Initialise the rest of the members of this class. Create the allocation 533cab2bb3Spatrick // pool using the provided options. See options.inc for runtime configuration 543cab2bb3Spatrick // options. 553cab2bb3Spatrick void init(const options::Options &Opts); 561f9cb04fSpatrick void uninitTestOnly(); 571f9cb04fSpatrick 581f9cb04fSpatrick // Functions exported for libmemunreachable's use on Android. disable() 591f9cb04fSpatrick // installs a lock in the allocator that prevents any thread from being able 601f9cb04fSpatrick // to allocate memory, until enable() is called. 611f9cb04fSpatrick void disable(); 621f9cb04fSpatrick void enable(); 631f9cb04fSpatrick 641f9cb04fSpatrick typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg); 651f9cb04fSpatrick // Execute the callback Cb for every allocation the lies in [Base, Base + 661f9cb04fSpatrick // Size). Must be called while the allocator is disabled. The callback can not 671f9cb04fSpatrick // allocate. 681f9cb04fSpatrick void iterate(void *Base, size_t Size, iterate_callback Cb, void *Arg); 691f9cb04fSpatrick 703cab2bb3Spatrick // Return whether the allocation should be randomly chosen for sampling. shouldSample()713cab2bb3Spatrick GWP_ASAN_ALWAYS_INLINE bool shouldSample() { 723cab2bb3Spatrick // NextSampleCounter == 0 means we "should regenerate the counter". 733cab2bb3Spatrick // == 1 means we "should sample this allocation". 741f9cb04fSpatrick // AdjustedSampleRatePlusOne is designed to intentionally underflow. This 751f9cb04fSpatrick // class must be valid when zero-initialised, and we wish to sample as 761f9cb04fSpatrick // infrequently as possible when this is the case, hence we underflow to 771f9cb04fSpatrick // UINT32_MAX. 78d89ec533Spatrick if (GWP_ASAN_UNLIKELY(getThreadLocals()->NextSampleCounter == 0)) 79d89ec533Spatrick getThreadLocals()->NextSampleCounter = 80d89ec533Spatrick ((getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1) & 81d89ec533Spatrick ThreadLocalPackedVariables::NextSampleCounterMask; 823cab2bb3Spatrick 83d89ec533Spatrick return GWP_ASAN_UNLIKELY(--getThreadLocals()->NextSampleCounter == 0); 843cab2bb3Spatrick } 853cab2bb3Spatrick 863cab2bb3Spatrick // Returns whether the provided pointer is a current sampled allocation that 873cab2bb3Spatrick // is owned by this pool. pointerIsMine(const void * Ptr)883cab2bb3Spatrick GWP_ASAN_ALWAYS_INLINE bool pointerIsMine(const void *Ptr) const { 891f9cb04fSpatrick return State.pointerIsMine(Ptr); 903cab2bb3Spatrick } 913cab2bb3Spatrick 92d89ec533Spatrick // Allocate memory in a guarded slot, with the specified `Alignment`. Returns 93d89ec533Spatrick // nullptr if the pool is empty, if the alignnment is not a power of two, or 94d89ec533Spatrick // if the size/alignment makes the allocation too large for this pool to 95d89ec533Spatrick // handle. By default, uses strong alignment (i.e. `max_align_t`), see 96d89ec533Spatrick // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm for discussion of 97d89ec533Spatrick // alignment issues in the standard. 98d89ec533Spatrick void *allocate(size_t Size, size_t Alignment = alignof(max_align_t)); 993cab2bb3Spatrick 1003cab2bb3Spatrick // Deallocate memory in a guarded slot. The provided pointer must have been 1013cab2bb3Spatrick // allocated using this pool. This will set the guarded slot as inaccessible. 1023cab2bb3Spatrick void deallocate(void *Ptr); 1033cab2bb3Spatrick 1043cab2bb3Spatrick // Returns the size of the allocation at Ptr. 1053cab2bb3Spatrick size_t getSize(const void *Ptr); 1063cab2bb3Spatrick 1071f9cb04fSpatrick // Returns a pointer to the Metadata region, or nullptr if it doesn't exist. getMetadataRegion()1081f9cb04fSpatrick const AllocationMetadata *getMetadataRegion() const { return Metadata; } 1093cab2bb3Spatrick 1101f9cb04fSpatrick // Returns a pointer to the AllocatorState region. getAllocatorState()1111f9cb04fSpatrick const AllocatorState *getAllocatorState() const { return &State; } 1123cab2bb3Spatrick 113*810390e3Srobert // Functions that the signal handler is responsible for calling, while 114*810390e3Srobert // providing the SEGV pointer, prior to dumping the crash, and after dumping 115*810390e3Srobert // the crash (in recoverable mode only). 116*810390e3Srobert void preCrashReport(void *Ptr); 117*810390e3Srobert void postCrashReportRecoverableOnly(void *Ptr); 118*810390e3Srobert 119d89ec533Spatrick // Exposed as protected for testing. 120d89ec533Spatrick protected: 121d89ec533Spatrick // Returns the actual allocation size required to service an allocation with 122d89ec533Spatrick // the provided Size and Alignment. 123d89ec533Spatrick static size_t getRequiredBackingSize(size_t Size, size_t Alignment, 124d89ec533Spatrick size_t PageSize); 125d89ec533Spatrick 126d89ec533Spatrick // Returns the provided pointer that meets the specified alignment, depending 127d89ec533Spatrick // on whether it's left or right aligned. 128d89ec533Spatrick static uintptr_t alignUp(uintptr_t Ptr, size_t Alignment); 129d89ec533Spatrick static uintptr_t alignDown(uintptr_t Ptr, size_t Alignment); 130d89ec533Spatrick 1313cab2bb3Spatrick private: 1321f9cb04fSpatrick // Name of actively-occupied slot mappings. 1331f9cb04fSpatrick static constexpr const char *kGwpAsanAliveSlotName = "GWP-ASan Alive Slot"; 1341f9cb04fSpatrick // Name of the guard pages. This includes all slots that are not actively in 1351f9cb04fSpatrick // use (i.e. were never used, or have been free()'d).) 1361f9cb04fSpatrick static constexpr const char *kGwpAsanGuardPageName = "GWP-ASan Guard Page"; 1371f9cb04fSpatrick // Name of the mapping for `FreeSlots`. 1381f9cb04fSpatrick static constexpr const char *kGwpAsanFreeSlotsName = "GWP-ASan Metadata"; 1391f9cb04fSpatrick 1403cab2bb3Spatrick static constexpr size_t kInvalidSlotID = SIZE_MAX; 1413cab2bb3Spatrick 1423cab2bb3Spatrick // These functions anonymously map memory or change the permissions of mapped 1433cab2bb3Spatrick // memory into this process in a platform-specific way. Pointer and size 1443cab2bb3Spatrick // arguments are expected to be page-aligned. These functions will never 1453cab2bb3Spatrick // return on error, instead electing to kill the calling process on failure. 146d89ec533Spatrick // The pool memory is initially reserved and inaccessible, and RW mappings are 147d89ec533Spatrick // subsequently created and destroyed via allocateInGuardedPool() and 148d89ec533Spatrick // deallocateInGuardedPool(). Each mapping is named on platforms that support 149d89ec533Spatrick // it, primarily Android. This name must be a statically allocated string, as 150d89ec533Spatrick // the Android kernel uses the string pointer directly. 151d89ec533Spatrick void *map(size_t Size, const char *Name) const; 152d89ec533Spatrick void unmap(void *Ptr, size_t Size) const; 153d89ec533Spatrick 154d89ec533Spatrick // The pool is managed separately, as some platforms (particularly Fuchsia) 155d89ec533Spatrick // manage virtual memory regions as a chunk where individual pages can still 156d89ec533Spatrick // have separate permissions. These platforms maintain metadata about the 157d89ec533Spatrick // region in order to perform operations. The pool is unique as it's the only 158d89ec533Spatrick // thing in GWP-ASan that treats pages in a single VM region on an individual 159d89ec533Spatrick // basis for page protection. 160d89ec533Spatrick // The pointer returned by reserveGuardedPool() is the reserved address range 161d89ec533Spatrick // of (at least) Size bytes. 162d89ec533Spatrick void *reserveGuardedPool(size_t Size); 163d89ec533Spatrick // allocateInGuardedPool() Ptr and Size must be a subrange of the previously 164d89ec533Spatrick // reserved pool range. 165d89ec533Spatrick void allocateInGuardedPool(void *Ptr, size_t Size) const; 166d89ec533Spatrick // deallocateInGuardedPool() Ptr and Size must be an exact pair previously 167d89ec533Spatrick // passed to allocateInGuardedPool(). 168d89ec533Spatrick void deallocateInGuardedPool(void *Ptr, size_t Size) const; 169d89ec533Spatrick void unreserveGuardedPool(); 1703cab2bb3Spatrick 1713cab2bb3Spatrick // Get the page size from the platform-specific implementation. Only needs to 1723cab2bb3Spatrick // be called once, and the result should be cached in PageSize in this class. 1733cab2bb3Spatrick static size_t getPlatformPageSize(); 1743cab2bb3Spatrick 1753cab2bb3Spatrick // Returns a pointer to the metadata for the owned pointer. If the pointer is 1763cab2bb3Spatrick // not owned by this pool, the result is undefined. 1773cab2bb3Spatrick AllocationMetadata *addrToMetadata(uintptr_t Ptr) const; 1783cab2bb3Spatrick 1793cab2bb3Spatrick // Reserve a slot for a new guarded allocation. Returns kInvalidSlotID if no 1803cab2bb3Spatrick // slot is available to be reserved. 1813cab2bb3Spatrick size_t reserveSlot(); 1823cab2bb3Spatrick 1833cab2bb3Spatrick // Unreserve the guarded slot. 1843cab2bb3Spatrick void freeSlot(size_t SlotIndex); 1853cab2bb3Spatrick 1861f9cb04fSpatrick // Raise a SEGV and set the corresponding fields in the Allocator's State in 1871f9cb04fSpatrick // order to tell the crash handler what happened. Used when errors are 1881f9cb04fSpatrick // detected internally (Double Free, Invalid Free). 189*810390e3Srobert void raiseInternallyDetectedError(uintptr_t Address, Error E); 1903cab2bb3Spatrick 1911f9cb04fSpatrick static GuardedPoolAllocator *getSingleton(); 1923cab2bb3Spatrick 1931f9cb04fSpatrick // Install a pthread_atfork handler. 1941f9cb04fSpatrick void installAtFork(); 1953cab2bb3Spatrick 1961f9cb04fSpatrick gwp_asan::AllocatorState State; 1973cab2bb3Spatrick 1983cab2bb3Spatrick // A mutex to protect the guarded slot and metadata pool for this class. 1993cab2bb3Spatrick Mutex PoolMutex; 200d89ec533Spatrick // Some unwinders can grab the libdl lock. In order to provide atfork 201d89ec533Spatrick // protection, we need to ensure that we allow an unwinding thread to release 202d89ec533Spatrick // the libdl lock before forking. 203d89ec533Spatrick Mutex BacktraceMutex; 2043cab2bb3Spatrick // Record the number allocations that we've sampled. We store this amount so 2053cab2bb3Spatrick // that we don't randomly choose to recycle a slot that previously had an 2063cab2bb3Spatrick // allocation before all the slots have been utilised. 2073cab2bb3Spatrick size_t NumSampledAllocations = 0; 2083cab2bb3Spatrick // Pointer to the allocation metadata (allocation/deallocation stack traces), 2093cab2bb3Spatrick // if any. 2103cab2bb3Spatrick AllocationMetadata *Metadata = nullptr; 2113cab2bb3Spatrick 2123cab2bb3Spatrick // Pointer to an array of free slot indexes. 2133cab2bb3Spatrick size_t *FreeSlots = nullptr; 2143cab2bb3Spatrick // The current length of the list of free slots. 2153cab2bb3Spatrick size_t FreeSlotsLength = 0; 2163cab2bb3Spatrick 2173cab2bb3Spatrick // See options.{h, inc} for more information. 2183cab2bb3Spatrick bool PerfectlyRightAlign = false; 2193cab2bb3Spatrick 2201f9cb04fSpatrick // Backtrace function provided by the supporting allocator. See `options.h` 2211f9cb04fSpatrick // for more information. 2223cab2bb3Spatrick options::Backtrace_t Backtrace = nullptr; 2233cab2bb3Spatrick 2243cab2bb3Spatrick // The adjusted sample rate for allocation sampling. Default *must* be 2253cab2bb3Spatrick // nonzero, as dynamic initialisation may call malloc (e.g. from libstdc++) 2263cab2bb3Spatrick // before GPA::init() is called. This would cause an error in shouldSample(), 2273cab2bb3Spatrick // where we would calculate modulo zero. This value is set UINT32_MAX, as when 2283cab2bb3Spatrick // GWP-ASan is disabled, we wish to never spend wasted cycles recalculating 2293cab2bb3Spatrick // the sample rate. 2301f9cb04fSpatrick uint32_t AdjustedSampleRatePlusOne = 0; 2313cab2bb3Spatrick 232d89ec533Spatrick // Additional platform specific data structure for the guarded pool mapping. 233d89ec533Spatrick PlatformSpecificMapData GuardedPagePoolPlatformData = {}; 234d89ec533Spatrick 235d89ec533Spatrick class ScopedRecursiveGuard { 236d89ec533Spatrick public: ScopedRecursiveGuard()237d89ec533Spatrick ScopedRecursiveGuard() { getThreadLocals()->RecursiveGuard = true; } ~ScopedRecursiveGuard()238d89ec533Spatrick ~ScopedRecursiveGuard() { getThreadLocals()->RecursiveGuard = false; } 2393cab2bb3Spatrick }; 240d89ec533Spatrick 241d89ec533Spatrick // Initialise the PRNG, platform-specific. 242d89ec533Spatrick void initPRNG(); 243d89ec533Spatrick 244d89ec533Spatrick // xorshift (32-bit output), extremely fast PRNG that uses arithmetic 245d89ec533Spatrick // operations only. Seeded using platform-specific mechanisms by initPRNG(). 246d89ec533Spatrick uint32_t getRandomUnsigned32(); 2473cab2bb3Spatrick }; 2483cab2bb3Spatrick } // namespace gwp_asan 2493cab2bb3Spatrick 2503cab2bb3Spatrick #endif // GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_ 251