guarded_pool_allocator.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. //===-- guarded_pool_allocator.h --------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #ifndef GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_
  9. #define GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_
  10. #include "gwp_asan/common.h"
  11. #include "gwp_asan/definitions.h"
  12. #include "gwp_asan/mutex.h"
  13. #include "gwp_asan/options.h"
  14. #include "gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.h" // IWYU pragma: keep
  15. #include "gwp_asan/platform_specific/guarded_pool_allocator_posix.h" // IWYU pragma: keep
  16. #include "gwp_asan/platform_specific/guarded_pool_allocator_tls.h"
  17. #include <stddef.h>
  18. #include <stdint.h>
  19. // IWYU pragma: no_include <__stddef_max_align_t.h>
  20. // IWYU pragma: no_include <__stddef_null.h>
  21. // IWYU pragma: no_include <__stddef_nullptr_t.h>
  22. // IWYU pragma: no_include <__stddef_offsetof.h>
  23. // IWYU pragma: no_include <__stddef_ptrdiff_t.h>
  24. // IWYU pragma: no_include <__stddef_rsize_t.h>
  25. // IWYU pragma: no_include <__stddef_size_t.h>
  26. // IWYU pragma: no_include <__stddef_unreachable.h>
  27. // IWYU pragma: no_include <__stddef_wchar_t.h>
  28. // IWYU pragma: no_include <__stddef_wint_t.h>
  29. namespace gwp_asan {
  30. // This class is the primary implementation of the allocator portion of GWP-
  31. // ASan. It is the sole owner of the pool of sequentially allocated guarded
  32. // slots. It should always be treated as a singleton.
  33. // Functions in the public interface of this class are thread-compatible until
  34. // init() is called, at which point they become thread-safe (unless specified
  35. // otherwise).
  36. class GuardedPoolAllocator {
  37. public:
  38. // Name of the GWP-ASan mapping that for `Metadata`.
  39. static constexpr const char *kGwpAsanMetadataName = "GWP-ASan Metadata";
  40. // During program startup, we must ensure that memory allocations do not land
  41. // in this allocation pool if the allocator decides to runtime-disable
  42. // GWP-ASan. The constructor value-initialises the class such that if no
  43. // further initialisation takes place, calls to shouldSample() and
  44. // pointerIsMine() will return false.
  45. constexpr GuardedPoolAllocator() {}
  46. GuardedPoolAllocator(const GuardedPoolAllocator &) = delete;
  47. GuardedPoolAllocator &operator=(const GuardedPoolAllocator &) = delete;
  48. // Note: This class is expected to be a singleton for the lifetime of the
  49. // program. If this object is initialised, it will leak the guarded page pool
  50. // and metadata allocations during destruction. We can't clean up these areas
  51. // as this may cause a use-after-free on shutdown.
  52. ~GuardedPoolAllocator() = default;
  53. // Initialise the rest of the members of this class. Create the allocation
  54. // pool using the provided options. See options.inc for runtime configuration
  55. // options.
  56. void init(const options::Options &Opts);
  57. void uninitTestOnly();
  58. // Functions exported for libmemunreachable's use on Android. disable()
  59. // installs a lock in the allocator that prevents any thread from being able
  60. // to allocate memory, until enable() is called.
  61. void disable();
  62. void enable();
  63. typedef void (*iterate_callback)(uintptr_t base, size_t size, void *arg);
  64. // Execute the callback Cb for every allocation the lies in [Base, Base +
  65. // Size). Must be called while the allocator is disabled. The callback can not
  66. // allocate.
  67. void iterate(void *Base, size_t Size, iterate_callback Cb, void *Arg);
  68. // Return whether the allocation should be randomly chosen for sampling.
  69. GWP_ASAN_ALWAYS_INLINE bool shouldSample() {
  70. // NextSampleCounter == 0 means we "should regenerate the counter".
  71. // == 1 means we "should sample this allocation".
  72. // AdjustedSampleRatePlusOne is designed to intentionally underflow. This
  73. // class must be valid when zero-initialised, and we wish to sample as
  74. // infrequently as possible when this is the case, hence we underflow to
  75. // UINT32_MAX.
  76. if (GWP_ASAN_UNLIKELY(getThreadLocals()->NextSampleCounter == 0))
  77. getThreadLocals()->NextSampleCounter =
  78. ((getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1) &
  79. ThreadLocalPackedVariables::NextSampleCounterMask;
  80. return GWP_ASAN_UNLIKELY(--getThreadLocals()->NextSampleCounter == 0);
  81. }
  82. // Returns whether the provided pointer is a current sampled allocation that
  83. // is owned by this pool.
  84. GWP_ASAN_ALWAYS_INLINE bool pointerIsMine(const void *Ptr) const {
  85. return State.pointerIsMine(Ptr);
  86. }
  87. // Allocate memory in a guarded slot, with the specified `Alignment`. Returns
  88. // nullptr if the pool is empty, if the alignnment is not a power of two, or
  89. // if the size/alignment makes the allocation too large for this pool to
  90. // handle. By default, uses strong alignment (i.e. `max_align_t`), see
  91. // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm for discussion of
  92. // alignment issues in the standard.
  93. void *allocate(size_t Size, size_t Alignment = alignof(max_align_t));
  94. // Deallocate memory in a guarded slot. The provided pointer must have been
  95. // allocated using this pool. This will set the guarded slot as inaccessible.
  96. void deallocate(void *Ptr);
  97. // Returns the size of the allocation at Ptr.
  98. size_t getSize(const void *Ptr);
  99. // Returns a pointer to the Metadata region, or nullptr if it doesn't exist.
  100. const AllocationMetadata *getMetadataRegion() const { return Metadata; }
  101. // Returns a pointer to the AllocatorState region.
  102. const AllocatorState *getAllocatorState() const { return &State; }
  103. // Functions that the signal handler is responsible for calling, while
  104. // providing the SEGV pointer, prior to dumping the crash, and after dumping
  105. // the crash (in recoverable mode only).
  106. void preCrashReport(void *Ptr);
  107. void postCrashReportRecoverableOnly(void *Ptr);
  108. // Exposed as protected for testing.
  109. protected:
  110. // Returns the actual allocation size required to service an allocation with
  111. // the provided Size and Alignment.
  112. static size_t getRequiredBackingSize(size_t Size, size_t Alignment,
  113. size_t PageSize);
  114. // Returns the provided pointer that meets the specified alignment, depending
  115. // on whether it's left or right aligned.
  116. static uintptr_t alignUp(uintptr_t Ptr, size_t Alignment);
  117. static uintptr_t alignDown(uintptr_t Ptr, size_t Alignment);
  118. private:
  119. // Name of actively-occupied slot mappings.
  120. static constexpr const char *kGwpAsanAliveSlotName = "GWP-ASan Alive Slot";
  121. // Name of the guard pages. This includes all slots that are not actively in
  122. // use (i.e. were never used, or have been free()'d).)
  123. static constexpr const char *kGwpAsanGuardPageName = "GWP-ASan Guard Page";
  124. // Name of the mapping for `FreeSlots`.
  125. static constexpr const char *kGwpAsanFreeSlotsName = "GWP-ASan Metadata";
  126. static constexpr size_t kInvalidSlotID = SIZE_MAX;
  127. // These functions anonymously map memory or change the permissions of mapped
  128. // memory into this process in a platform-specific way. Pointer and size
  129. // arguments are expected to be page-aligned. These functions will never
  130. // return on error, instead electing to kill the calling process on failure.
  131. // The pool memory is initially reserved and inaccessible, and RW mappings are
  132. // subsequently created and destroyed via allocateInGuardedPool() and
  133. // deallocateInGuardedPool(). Each mapping is named on platforms that support
  134. // it, primarily Android. This name must be a statically allocated string, as
  135. // the Android kernel uses the string pointer directly.
  136. void *map(size_t Size, const char *Name) const;
  137. void unmap(void *Ptr, size_t Size) const;
  138. // The pool is managed separately, as some platforms (particularly Fuchsia)
  139. // manage virtual memory regions as a chunk where individual pages can still
  140. // have separate permissions. These platforms maintain metadata about the
  141. // region in order to perform operations. The pool is unique as it's the only
  142. // thing in GWP-ASan that treats pages in a single VM region on an individual
  143. // basis for page protection.
  144. // The pointer returned by reserveGuardedPool() is the reserved address range
  145. // of (at least) Size bytes.
  146. void *reserveGuardedPool(size_t Size);
  147. // allocateInGuardedPool() Ptr and Size must be a subrange of the previously
  148. // reserved pool range.
  149. void allocateInGuardedPool(void *Ptr, size_t Size) const;
  150. // deallocateInGuardedPool() Ptr and Size must be an exact pair previously
  151. // passed to allocateInGuardedPool().
  152. void deallocateInGuardedPool(void *Ptr, size_t Size) const;
  153. void unreserveGuardedPool();
  154. // Get the page size from the platform-specific implementation. Only needs to
  155. // be called once, and the result should be cached in PageSize in this class.
  156. static size_t getPlatformPageSize();
  157. // Returns a pointer to the metadata for the owned pointer. If the pointer is
  158. // not owned by this pool, the result is undefined.
  159. AllocationMetadata *addrToMetadata(uintptr_t Ptr) const;
  160. // Reserve a slot for a new guarded allocation. Returns kInvalidSlotID if no
  161. // slot is available to be reserved.
  162. size_t reserveSlot();
  163. // Unreserve the guarded slot.
  164. void freeSlot(size_t SlotIndex);
  165. // Raise a SEGV and set the corresponding fields in the Allocator's State in
  166. // order to tell the crash handler what happened. Used when errors are
  167. // detected internally (Double Free, Invalid Free).
  168. void raiseInternallyDetectedError(uintptr_t Address, Error E);
  169. static GuardedPoolAllocator *getSingleton();
  170. // Install a pthread_atfork handler.
  171. void installAtFork();
  172. gwp_asan::AllocatorState State;
  173. // A mutex to protect the guarded slot and metadata pool for this class.
  174. Mutex PoolMutex;
  175. // Some unwinders can grab the libdl lock. In order to provide atfork
  176. // protection, we need to ensure that we allow an unwinding thread to release
  177. // the libdl lock before forking.
  178. Mutex BacktraceMutex;
  179. // Record the number allocations that we've sampled. We store this amount so
  180. // that we don't randomly choose to recycle a slot that previously had an
  181. // allocation before all the slots have been utilised.
  182. size_t NumSampledAllocations = 0;
  183. // Pointer to the allocation metadata (allocation/deallocation stack traces),
  184. // if any.
  185. AllocationMetadata *Metadata = nullptr;
  186. // Pointer to an array of free slot indexes.
  187. size_t *FreeSlots = nullptr;
  188. // The current length of the list of free slots.
  189. size_t FreeSlotsLength = 0;
  190. // See options.{h, inc} for more information.
  191. bool PerfectlyRightAlign = false;
  192. // Backtrace function provided by the supporting allocator. See `options.h`
  193. // for more information.
  194. options::Backtrace_t Backtrace = nullptr;
  195. // The adjusted sample rate for allocation sampling. Default *must* be
  196. // nonzero, as dynamic initialisation may call malloc (e.g. from libstdc++)
  197. // before GPA::init() is called. This would cause an error in shouldSample(),
  198. // where we would calculate modulo zero. This value is set UINT32_MAX, as when
  199. // GWP-ASan is disabled, we wish to never spend wasted cycles recalculating
  200. // the sample rate.
  201. uint32_t AdjustedSampleRatePlusOne = 0;
  202. // Additional platform specific data structure for the guarded pool mapping.
  203. PlatformSpecificMapData GuardedPagePoolPlatformData = {};
  204. class ScopedRecursiveGuard {
  205. public:
  206. ScopedRecursiveGuard() { getThreadLocals()->RecursiveGuard = true; }
  207. ~ScopedRecursiveGuard() { getThreadLocals()->RecursiveGuard = false; }
  208. };
  209. // Initialise the PRNG, platform-specific.
  210. void initPRNG();
  211. // xorshift (32-bit output), extremely fast PRNG that uses arithmetic
  212. // operations only. Seeded using platform-specific mechanisms by initPRNG().
  213. uint32_t getRandomUnsigned32();
  214. };
  215. } // namespace gwp_asan
  216. #endif // GWP_ASAN_GUARDED_POOL_ALLOCATOR_H_