1 //===-- hwasan_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 // 9 // This file is a part of HWAddressSanitizer. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef HWASAN_ALLOCATOR_H 14 #define HWASAN_ALLOCATOR_H 15 16 #include "hwasan.h" 17 #include "hwasan_interface_internal.h" 18 #include "hwasan_mapping.h" 19 #include "hwasan_poisoning.h" 20 #include "lsan/lsan_common.h" 21 #include "sanitizer_common/sanitizer_allocator.h" 22 #include "sanitizer_common/sanitizer_allocator_checks.h" 23 #include "sanitizer_common/sanitizer_allocator_interface.h" 24 #include "sanitizer_common/sanitizer_allocator_report.h" 25 #include "sanitizer_common/sanitizer_common.h" 26 #include "sanitizer_common/sanitizer_ring_buffer.h" 27 28 #if !defined(__aarch64__) && !defined(__x86_64__) && !(SANITIZER_RISCV64) 29 # error Unsupported platform 30 #endif 31 32 namespace __hwasan { 33 34 struct Metadata { 35 private: 36 atomic_uint64_t alloc_context_id; 37 u32 requested_size_low; 38 u16 requested_size_high; 39 atomic_uint8_t chunk_state; 40 u8 lsan_tag; 41 42 public: 43 inline void SetAllocated(u32 stack, u64 size); 44 inline void SetUnallocated(); 45 46 inline bool IsAllocated() const; 47 inline u64 GetRequestedSize() const; 48 inline u32 GetAllocStackId() const; 49 inline void SetLsanTag(__lsan::ChunkTag tag); 50 inline __lsan::ChunkTag GetLsanTag() const; 51 }; 52 static_assert(sizeof(Metadata) == 16); 53 54 struct HwasanMapUnmapCallback { 55 void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); } 56 void OnUnmap(uptr p, uptr size) const { 57 // We are about to unmap a chunk of user memory. 58 // It can return as user-requested mmap() or another thread stack. 59 // Make it accessible with zero-tagged pointer. 60 TagMemory(p, size, 0); 61 } 62 }; 63 64 static const uptr kMaxAllowedMallocSize = 1UL << 40; // 1T 65 66 struct AP64 { 67 static const uptr kSpaceBeg = ~0ULL; 68 69 #if defined(HWASAN_ALIASING_MODE) 70 static const uptr kSpaceSize = 1ULL << kAddressTagShift; 71 #else 72 static const uptr kSpaceSize = 0x2000000000ULL; 73 #endif 74 static const uptr kMetadataSize = sizeof(Metadata); 75 typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap; 76 using AddressSpaceView = LocalAddressSpaceView; 77 typedef HwasanMapUnmapCallback MapUnmapCallback; 78 static const uptr kFlags = 0; 79 }; 80 typedef SizeClassAllocator64<AP64> PrimaryAllocator; 81 typedef CombinedAllocator<PrimaryAllocator> Allocator; 82 typedef Allocator::AllocatorCache AllocatorCache; 83 84 void AllocatorSwallowThreadLocalCache(AllocatorCache *cache); 85 86 class HwasanChunkView { 87 public: 88 HwasanChunkView() : block_(0), metadata_(nullptr) {} 89 HwasanChunkView(uptr block, Metadata *metadata) 90 : block_(block), metadata_(metadata) {} 91 bool IsAllocated() const; // Checks if the memory is currently allocated 92 uptr Beg() const; // First byte of user memory 93 uptr End() const; // Last byte of user memory 94 uptr UsedSize() const; // Size requested by the user 95 uptr ActualSize() const; // Size allocated by the allocator. 96 u32 GetAllocStackId() const; 97 bool FromSmallHeap() const; 98 bool AddrIsInside(uptr addr) const; 99 100 private: 101 friend class __lsan::LsanMetadata; 102 uptr block_; 103 Metadata *const metadata_; 104 }; 105 106 HwasanChunkView FindHeapChunkByAddress(uptr address); 107 108 // Information about one (de)allocation that happened in the past. 109 // These are recorded in a thread-local ring buffer. 110 // TODO: this is currently 24 bytes (20 bytes + alignment). 111 // Compress it to 16 bytes or extend it to be more useful. 112 struct HeapAllocationRecord { 113 uptr tagged_addr; 114 u32 alloc_context_id; 115 u32 free_context_id; 116 u32 requested_size; 117 }; 118 119 typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer; 120 121 void GetAllocatorStats(AllocatorStatCounters s); 122 123 inline bool InTaggableRegion(uptr addr) { 124 #if defined(HWASAN_ALIASING_MODE) 125 // Aliases are mapped next to shadow so that the upper bits match the shadow 126 // base. 127 return (addr >> kTaggableRegionCheckShift) == 128 (GetShadowOffset() >> kTaggableRegionCheckShift); 129 #endif 130 return true; 131 } 132 133 } // namespace __hwasan 134 135 #endif // HWASAN_ALLOCATOR_H 136