Home | History | Annotate | Line # | Download | only in hwasan
      1      1.1  mrg //===-- hwasan_allocator.cpp ------------------------ ---------------------===//
      2      1.1  mrg //
      3      1.1  mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4      1.1  mrg // See https://llvm.org/LICENSE.txt for license information.
      5      1.1  mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6      1.1  mrg //
      7      1.1  mrg //===----------------------------------------------------------------------===//
      8      1.1  mrg //
      9      1.1  mrg // This file is a part of HWAddressSanitizer.
     10      1.1  mrg //
     11      1.1  mrg // HWAddressSanitizer allocator.
     12      1.1  mrg //===----------------------------------------------------------------------===//
     13      1.1  mrg 
     14      1.1  mrg #include "sanitizer_common/sanitizer_atomic.h"
     15      1.1  mrg #include "sanitizer_common/sanitizer_errno.h"
     16      1.1  mrg #include "sanitizer_common/sanitizer_stackdepot.h"
     17      1.1  mrg #include "hwasan.h"
     18      1.1  mrg #include "hwasan_allocator.h"
     19      1.1  mrg #include "hwasan_checks.h"
     20      1.1  mrg #include "hwasan_mapping.h"
     21      1.1  mrg #include "hwasan_malloc_bisect.h"
     22      1.1  mrg #include "hwasan_thread.h"
     23      1.1  mrg #include "hwasan_report.h"
     24  1.1.1.2  mrg #include "lsan/lsan_common.h"
     25      1.1  mrg 
     26      1.1  mrg namespace __hwasan {
     27      1.1  mrg 
     28      1.1  mrg static Allocator allocator;
     29      1.1  mrg static AllocatorCache fallback_allocator_cache;
     30      1.1  mrg static SpinMutex fallback_mutex;
     31      1.1  mrg static atomic_uint8_t hwasan_allocator_tagging_enabled;
     32      1.1  mrg 
     33      1.1  mrg static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
     34      1.1  mrg static constexpr tag_t kFallbackFreeTag = 0xBC;
     35      1.1  mrg 
     36  1.1.1.2  mrg enum {
     37  1.1.1.2  mrg   // Either just allocated by underlying allocator, but AsanChunk is not yet
     38  1.1.1.2  mrg   // ready, or almost returned to undelying allocator and AsanChunk is already
     39  1.1.1.2  mrg   // meaningless.
     40  1.1.1.2  mrg   CHUNK_INVALID = 0,
     41  1.1.1.2  mrg   // The chunk is allocated and not yet freed.
     42  1.1.1.2  mrg   CHUNK_ALLOCATED = 1,
     43      1.1  mrg };
     44      1.1  mrg 
     45  1.1.1.2  mrg 
     46      1.1  mrg // Initialized in HwasanAllocatorInit, an never changed.
     47      1.1  mrg static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1];
     48  1.1.1.2  mrg static uptr max_malloc_size;
     49      1.1  mrg 
     50      1.1  mrg bool HwasanChunkView::IsAllocated() const {
     51  1.1.1.2  mrg   return metadata_ && metadata_->IsAllocated();
     52      1.1  mrg }
     53      1.1  mrg 
     54      1.1  mrg uptr HwasanChunkView::Beg() const {
     55      1.1  mrg   return block_;
     56      1.1  mrg }
     57      1.1  mrg uptr HwasanChunkView::End() const {
     58      1.1  mrg   return Beg() + UsedSize();
     59      1.1  mrg }
     60      1.1  mrg uptr HwasanChunkView::UsedSize() const {
     61  1.1.1.2  mrg   return metadata_->GetRequestedSize();
     62      1.1  mrg }
     63      1.1  mrg u32 HwasanChunkView::GetAllocStackId() const {
     64  1.1.1.2  mrg   return metadata_->GetAllocStackId();
     65  1.1.1.2  mrg }
     66  1.1.1.2  mrg 
     67  1.1.1.2  mrg u32 HwasanChunkView::GetAllocThreadId() const {
     68  1.1.1.2  mrg   return metadata_->GetAllocThreadId();
     69      1.1  mrg }
     70      1.1  mrg 
     71      1.1  mrg uptr HwasanChunkView::ActualSize() const {
     72      1.1  mrg   return allocator.GetActuallyAllocatedSize(reinterpret_cast<void *>(block_));
     73      1.1  mrg }
     74      1.1  mrg 
     75      1.1  mrg bool HwasanChunkView::FromSmallHeap() const {
     76      1.1  mrg   return allocator.FromPrimary(reinterpret_cast<void *>(block_));
     77      1.1  mrg }
     78      1.1  mrg 
     79  1.1.1.2  mrg bool HwasanChunkView::AddrIsInside(uptr addr) const {
     80  1.1.1.2  mrg   return (addr >= Beg()) && (addr < Beg() + UsedSize());
     81  1.1.1.2  mrg }
     82  1.1.1.2  mrg 
     83  1.1.1.2  mrg inline void Metadata::SetAllocated(u32 stack, u64 size) {
     84  1.1.1.2  mrg   Thread *t = GetCurrentThread();
     85  1.1.1.2  mrg   u64 context = t ? t->unique_id() : kMainTid;
     86  1.1.1.2  mrg   context <<= 32;
     87  1.1.1.2  mrg   context += stack;
     88  1.1.1.2  mrg   requested_size_low = size & ((1ul << 32) - 1);
     89  1.1.1.2  mrg   requested_size_high = size >> 32;
     90  1.1.1.2  mrg   atomic_store(&alloc_context_id, context, memory_order_relaxed);
     91  1.1.1.2  mrg   atomic_store(&chunk_state, CHUNK_ALLOCATED, memory_order_release);
     92  1.1.1.2  mrg }
     93  1.1.1.2  mrg 
     94  1.1.1.2  mrg inline void Metadata::SetUnallocated() {
     95  1.1.1.2  mrg   atomic_store(&chunk_state, CHUNK_INVALID, memory_order_release);
     96  1.1.1.2  mrg   requested_size_low = 0;
     97  1.1.1.2  mrg   requested_size_high = 0;
     98  1.1.1.2  mrg   atomic_store(&alloc_context_id, 0, memory_order_relaxed);
     99  1.1.1.2  mrg }
    100  1.1.1.2  mrg 
    101  1.1.1.2  mrg inline bool Metadata::IsAllocated() const {
    102  1.1.1.2  mrg   return atomic_load(&chunk_state, memory_order_relaxed) == CHUNK_ALLOCATED;
    103  1.1.1.2  mrg }
    104  1.1.1.2  mrg 
    105  1.1.1.2  mrg inline u64 Metadata::GetRequestedSize() const {
    106  1.1.1.2  mrg   return (static_cast<u64>(requested_size_high) << 32) + requested_size_low;
    107  1.1.1.2  mrg }
    108  1.1.1.2  mrg 
    109  1.1.1.2  mrg inline u32 Metadata::GetAllocStackId() const {
    110  1.1.1.2  mrg   return atomic_load(&alloc_context_id, memory_order_relaxed);
    111  1.1.1.2  mrg }
    112  1.1.1.2  mrg 
    113  1.1.1.2  mrg inline u32 Metadata::GetAllocThreadId() const {
    114  1.1.1.2  mrg   u64 context = atomic_load(&alloc_context_id, memory_order_relaxed);
    115  1.1.1.2  mrg   u32 tid = context >> 32;
    116  1.1.1.2  mrg   return tid;
    117  1.1.1.2  mrg }
    118  1.1.1.2  mrg 
    119      1.1  mrg void GetAllocatorStats(AllocatorStatCounters s) {
    120      1.1  mrg   allocator.GetStats(s);
    121      1.1  mrg }
    122      1.1  mrg 
    123  1.1.1.2  mrg inline void Metadata::SetLsanTag(__lsan::ChunkTag tag) {
    124  1.1.1.2  mrg   lsan_tag = tag;
    125  1.1.1.2  mrg }
    126  1.1.1.2  mrg 
    127  1.1.1.2  mrg inline __lsan::ChunkTag Metadata::GetLsanTag() const {
    128  1.1.1.2  mrg   return static_cast<__lsan::ChunkTag>(lsan_tag);
    129  1.1.1.2  mrg }
    130  1.1.1.2  mrg 
    131      1.1  mrg uptr GetAliasRegionStart() {
    132      1.1  mrg #if defined(HWASAN_ALIASING_MODE)
    133      1.1  mrg   constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
    134      1.1  mrg   uptr AliasRegionStart =
    135      1.1  mrg       __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
    136      1.1  mrg 
    137      1.1  mrg   CHECK_EQ(AliasRegionStart >> kTaggableRegionCheckShift,
    138      1.1  mrg            __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
    139      1.1  mrg   CHECK_EQ(
    140      1.1  mrg       (AliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
    141      1.1  mrg       __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
    142      1.1  mrg   return AliasRegionStart;
    143      1.1  mrg #else
    144      1.1  mrg   return 0;
    145      1.1  mrg #endif
    146      1.1  mrg }
    147      1.1  mrg 
    148      1.1  mrg void HwasanAllocatorInit() {
    149      1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
    150      1.1  mrg                        !flags()->disable_allocator_tagging);
    151      1.1  mrg   SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
    152  1.1.1.2  mrg   allocator.InitLinkerInitialized(
    153  1.1.1.2  mrg       common_flags()->allocator_release_to_os_interval_ms,
    154  1.1.1.2  mrg       GetAliasRegionStart());
    155      1.1  mrg   for (uptr i = 0; i < sizeof(tail_magic); i++)
    156      1.1  mrg     tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
    157  1.1.1.2  mrg   if (common_flags()->max_allocation_size_mb) {
    158  1.1.1.2  mrg     max_malloc_size = common_flags()->max_allocation_size_mb << 20;
    159  1.1.1.2  mrg     max_malloc_size = Min(max_malloc_size, kMaxAllowedMallocSize);
    160  1.1.1.2  mrg   } else {
    161  1.1.1.2  mrg     max_malloc_size = kMaxAllowedMallocSize;
    162  1.1.1.2  mrg   }
    163      1.1  mrg }
    164      1.1  mrg 
    165      1.1  mrg void HwasanAllocatorLock() { allocator.ForceLock(); }
    166      1.1  mrg 
    167      1.1  mrg void HwasanAllocatorUnlock() { allocator.ForceUnlock(); }
    168      1.1  mrg 
    169  1.1.1.2  mrg void AllocatorThreadStart(AllocatorCache *cache) { allocator.InitCache(cache); }
    170  1.1.1.2  mrg 
    171  1.1.1.2  mrg void AllocatorThreadFinish(AllocatorCache *cache) {
    172      1.1  mrg   allocator.SwallowCache(cache);
    173  1.1.1.2  mrg   allocator.DestroyCache(cache);
    174      1.1  mrg }
    175      1.1  mrg 
    176      1.1  mrg static uptr TaggedSize(uptr size) {
    177      1.1  mrg   if (!size) size = 1;
    178      1.1  mrg   uptr new_size = RoundUpTo(size, kShadowAlignment);
    179      1.1  mrg   CHECK_GE(new_size, size);
    180      1.1  mrg   return new_size;
    181      1.1  mrg }
    182      1.1  mrg 
    183      1.1  mrg static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
    184      1.1  mrg                             bool zeroise) {
    185  1.1.1.2  mrg   // Keep this consistent with LSAN and ASAN behavior.
    186  1.1.1.2  mrg   if (UNLIKELY(orig_size == 0))
    187  1.1.1.2  mrg     orig_size = 1;
    188  1.1.1.2  mrg   if (UNLIKELY(orig_size > max_malloc_size)) {
    189      1.1  mrg     if (AllocatorMayReturnNull()) {
    190      1.1  mrg       Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
    191      1.1  mrg              orig_size);
    192      1.1  mrg       return nullptr;
    193      1.1  mrg     }
    194  1.1.1.2  mrg     ReportAllocationSizeTooBig(orig_size, max_malloc_size, stack);
    195  1.1.1.2  mrg   }
    196  1.1.1.2  mrg   if (UNLIKELY(IsRssLimitExceeded())) {
    197  1.1.1.2  mrg     if (AllocatorMayReturnNull())
    198  1.1.1.2  mrg       return nullptr;
    199  1.1.1.2  mrg     ReportRssLimitExceeded(stack);
    200      1.1  mrg   }
    201      1.1  mrg 
    202      1.1  mrg   alignment = Max(alignment, kShadowAlignment);
    203      1.1  mrg   uptr size = TaggedSize(orig_size);
    204      1.1  mrg   Thread *t = GetCurrentThread();
    205      1.1  mrg   void *allocated;
    206      1.1  mrg   if (t) {
    207      1.1  mrg     allocated = allocator.Allocate(t->allocator_cache(), size, alignment);
    208      1.1  mrg   } else {
    209      1.1  mrg     SpinMutexLock l(&fallback_mutex);
    210      1.1  mrg     AllocatorCache *cache = &fallback_allocator_cache;
    211      1.1  mrg     allocated = allocator.Allocate(cache, size, alignment);
    212      1.1  mrg   }
    213      1.1  mrg   if (UNLIKELY(!allocated)) {
    214      1.1  mrg     SetAllocatorOutOfMemory();
    215      1.1  mrg     if (AllocatorMayReturnNull())
    216      1.1  mrg       return nullptr;
    217      1.1  mrg     ReportOutOfMemory(size, stack);
    218      1.1  mrg   }
    219      1.1  mrg   if (zeroise) {
    220  1.1.1.2  mrg     // The secondary allocator mmaps memory, which should be zero-inited so we
    221  1.1.1.2  mrg     // don't need to explicitly clear it.
    222  1.1.1.2  mrg     if (allocator.FromPrimary(allocated))
    223  1.1.1.2  mrg       internal_memset(allocated, 0, size);
    224      1.1  mrg   } else if (flags()->max_malloc_fill_size > 0) {
    225      1.1  mrg     uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
    226      1.1  mrg     internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
    227      1.1  mrg   }
    228      1.1  mrg   if (size != orig_size) {
    229      1.1  mrg     u8 *tail = reinterpret_cast<u8 *>(allocated) + orig_size;
    230      1.1  mrg     uptr tail_length = size - orig_size;
    231      1.1  mrg     internal_memcpy(tail, tail_magic, tail_length - 1);
    232      1.1  mrg     // Short granule is excluded from magic tail, so we explicitly untag.
    233      1.1  mrg     tail[tail_length - 1] = 0;
    234      1.1  mrg   }
    235      1.1  mrg 
    236      1.1  mrg   void *user_ptr = allocated;
    237      1.1  mrg   if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
    238  1.1.1.2  mrg       atomic_load_relaxed(&hwasan_allocator_tagging_enabled) &&
    239  1.1.1.2  mrg       flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
    240  1.1.1.2  mrg     tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
    241  1.1.1.2  mrg     uptr tag_size = orig_size ? orig_size : 1;
    242  1.1.1.2  mrg     uptr full_granule_size = RoundDownTo(tag_size, kShadowAlignment);
    243  1.1.1.2  mrg     user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, full_granule_size, tag);
    244  1.1.1.2  mrg     if (full_granule_size != tag_size) {
    245  1.1.1.2  mrg       u8 *short_granule = reinterpret_cast<u8 *>(allocated) + full_granule_size;
    246  1.1.1.2  mrg       TagMemoryAligned((uptr)short_granule, kShadowAlignment,
    247  1.1.1.2  mrg                        tag_size % kShadowAlignment);
    248  1.1.1.2  mrg       short_granule[kShadowAlignment - 1] = tag;
    249      1.1  mrg     }
    250  1.1.1.2  mrg   } else {
    251  1.1.1.2  mrg     // Tagging can not be completely skipped. If it's disabled, we need to tag
    252  1.1.1.2  mrg     // with zeros.
    253  1.1.1.2  mrg     user_ptr = (void *)TagMemoryAligned((uptr)user_ptr, size, 0);
    254      1.1  mrg   }
    255      1.1  mrg 
    256  1.1.1.2  mrg   Metadata *meta =
    257  1.1.1.2  mrg       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
    258  1.1.1.2  mrg #if CAN_SANITIZE_LEAKS
    259  1.1.1.2  mrg   meta->SetLsanTag(__lsan::DisabledInThisThread() ? __lsan::kIgnored
    260  1.1.1.2  mrg                                                   : __lsan::kDirectlyLeaked);
    261  1.1.1.2  mrg #endif
    262  1.1.1.2  mrg   meta->SetAllocated(StackDepotPut(*stack), orig_size);
    263  1.1.1.2  mrg   RunMallocHooks(user_ptr, orig_size);
    264      1.1  mrg   return user_ptr;
    265      1.1  mrg }
    266      1.1  mrg 
    267      1.1  mrg static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
    268      1.1  mrg   CHECK(tagged_ptr);
    269      1.1  mrg   uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
    270      1.1  mrg   if (!InTaggableRegion(tagged_uptr))
    271      1.1  mrg     return true;
    272      1.1  mrg   tag_t mem_tag = *reinterpret_cast<tag_t *>(
    273      1.1  mrg       MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
    274      1.1  mrg   return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
    275      1.1  mrg }
    276      1.1  mrg 
    277      1.1  mrg static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr,
    278      1.1  mrg                              void *tagged_ptr) {
    279      1.1  mrg   // This function can return true if halt_on_error is false.
    280      1.1  mrg   if (!MemIsApp(reinterpret_cast<uptr>(untagged_ptr)) ||
    281      1.1  mrg       !PointerAndMemoryTagsMatch(tagged_ptr)) {
    282      1.1  mrg     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
    283      1.1  mrg     return true;
    284      1.1  mrg   }
    285      1.1  mrg   return false;
    286      1.1  mrg }
    287      1.1  mrg 
    288      1.1  mrg static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
    289      1.1  mrg   CHECK(tagged_ptr);
    290  1.1.1.2  mrg   void *untagged_ptr = UntagPtr(tagged_ptr);
    291      1.1  mrg 
    292      1.1  mrg   if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr))
    293      1.1  mrg     return;
    294      1.1  mrg 
    295      1.1  mrg   void *aligned_ptr = reinterpret_cast<void *>(
    296      1.1  mrg       RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
    297      1.1  mrg   tag_t pointer_tag = GetTagFromPointer(reinterpret_cast<uptr>(tagged_ptr));
    298      1.1  mrg   Metadata *meta =
    299      1.1  mrg       reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
    300      1.1  mrg   if (!meta) {
    301      1.1  mrg     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
    302      1.1  mrg     return;
    303      1.1  mrg   }
    304  1.1.1.2  mrg 
    305  1.1.1.2  mrg   RunFreeHooks(tagged_ptr);
    306  1.1.1.2  mrg 
    307  1.1.1.2  mrg   uptr orig_size = meta->GetRequestedSize();
    308      1.1  mrg   u32 free_context_id = StackDepotPut(*stack);
    309  1.1.1.2  mrg   u32 alloc_context_id = meta->GetAllocStackId();
    310  1.1.1.2  mrg   u32 alloc_thread_id = meta->GetAllocThreadId();
    311  1.1.1.2  mrg 
    312  1.1.1.2  mrg   bool in_taggable_region =
    313  1.1.1.2  mrg       InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr));
    314      1.1  mrg 
    315      1.1  mrg   // Check tail magic.
    316      1.1  mrg   uptr tagged_size = TaggedSize(orig_size);
    317      1.1  mrg   if (flags()->free_checks_tail_magic && orig_size &&
    318      1.1  mrg       tagged_size != orig_size) {
    319      1.1  mrg     uptr tail_size = tagged_size - orig_size - 1;
    320      1.1  mrg     CHECK_LT(tail_size, kShadowAlignment);
    321      1.1  mrg     void *tail_beg = reinterpret_cast<void *>(
    322      1.1  mrg         reinterpret_cast<uptr>(aligned_ptr) + orig_size);
    323      1.1  mrg     tag_t short_granule_memtag = *(reinterpret_cast<tag_t *>(
    324      1.1  mrg         reinterpret_cast<uptr>(tail_beg) + tail_size));
    325      1.1  mrg     if (tail_size &&
    326      1.1  mrg         (internal_memcmp(tail_beg, tail_magic, tail_size) ||
    327      1.1  mrg          (in_taggable_region && pointer_tag != short_granule_memtag)))
    328      1.1  mrg       ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
    329      1.1  mrg                             orig_size, tail_magic);
    330      1.1  mrg   }
    331      1.1  mrg 
    332  1.1.1.2  mrg   // TODO(kstoimenov): consider meta->SetUnallocated(free_context_id).
    333  1.1.1.2  mrg   meta->SetUnallocated();
    334      1.1  mrg   // This memory will not be reused by anyone else, so we are free to keep it
    335      1.1  mrg   // poisoned.
    336      1.1  mrg   Thread *t = GetCurrentThread();
    337      1.1  mrg   if (flags()->max_free_fill_size > 0) {
    338      1.1  mrg     uptr fill_size =
    339      1.1  mrg         Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
    340      1.1  mrg     internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
    341      1.1  mrg   }
    342      1.1  mrg   if (in_taggable_region && flags()->tag_in_free && malloc_bisect(stack, 0) &&
    343  1.1.1.2  mrg       atomic_load_relaxed(&hwasan_allocator_tagging_enabled) &&
    344  1.1.1.2  mrg       allocator.FromPrimary(untagged_ptr) /* Secondary 0-tag and unmap.*/) {
    345      1.1  mrg     // Always store full 8-bit tags on free to maximize UAF detection.
    346      1.1  mrg     tag_t tag;
    347      1.1  mrg     if (t) {
    348      1.1  mrg       // Make sure we are not using a short granule tag as a poison tag. This
    349      1.1  mrg       // would make us attempt to read the memory on a UaF.
    350      1.1  mrg       // The tag can be zero if tagging is disabled on this thread.
    351      1.1  mrg       do {
    352      1.1  mrg         tag = t->GenerateRandomTag(/*num_bits=*/8);
    353      1.1  mrg       } while (
    354      1.1  mrg           UNLIKELY((tag < kShadowAlignment || tag == pointer_tag) && tag != 0));
    355      1.1  mrg     } else {
    356      1.1  mrg       static_assert(kFallbackFreeTag >= kShadowAlignment,
    357      1.1  mrg                     "fallback tag must not be a short granule tag.");
    358      1.1  mrg       tag = kFallbackFreeTag;
    359      1.1  mrg     }
    360      1.1  mrg     TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
    361      1.1  mrg                      tag);
    362      1.1  mrg   }
    363      1.1  mrg   if (t) {
    364      1.1  mrg     allocator.Deallocate(t->allocator_cache(), aligned_ptr);
    365      1.1  mrg     if (auto *ha = t->heap_allocations())
    366  1.1.1.2  mrg       ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_thread_id,
    367  1.1.1.2  mrg                 alloc_context_id, free_context_id,
    368  1.1.1.2  mrg                 static_cast<u32>(orig_size)});
    369      1.1  mrg   } else {
    370      1.1  mrg     SpinMutexLock l(&fallback_mutex);
    371      1.1  mrg     AllocatorCache *cache = &fallback_allocator_cache;
    372      1.1  mrg     allocator.Deallocate(cache, aligned_ptr);
    373      1.1  mrg   }
    374      1.1  mrg }
    375      1.1  mrg 
    376      1.1  mrg static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
    377      1.1  mrg                               uptr new_size, uptr alignment) {
    378  1.1.1.2  mrg   void *untagged_ptr_old = UntagPtr(tagged_ptr_old);
    379      1.1  mrg   if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old))
    380      1.1  mrg     return nullptr;
    381      1.1  mrg   void *tagged_ptr_new =
    382      1.1  mrg       HwasanAllocate(stack, new_size, alignment, false /*zeroise*/);
    383      1.1  mrg   if (tagged_ptr_old && tagged_ptr_new) {
    384      1.1  mrg     Metadata *meta =
    385      1.1  mrg         reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
    386  1.1.1.2  mrg     void *untagged_ptr_new = UntagPtr(tagged_ptr_new);
    387  1.1.1.2  mrg     internal_memcpy(untagged_ptr_new, untagged_ptr_old,
    388  1.1.1.2  mrg                     Min(new_size, static_cast<uptr>(meta->GetRequestedSize())));
    389      1.1  mrg     HwasanDeallocate(stack, tagged_ptr_old);
    390      1.1  mrg   }
    391      1.1  mrg   return tagged_ptr_new;
    392      1.1  mrg }
    393      1.1  mrg 
    394      1.1  mrg static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
    395      1.1  mrg   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
    396      1.1  mrg     if (AllocatorMayReturnNull())
    397      1.1  mrg       return nullptr;
    398      1.1  mrg     ReportCallocOverflow(nmemb, size, stack);
    399      1.1  mrg   }
    400      1.1  mrg   return HwasanAllocate(stack, nmemb * size, sizeof(u64), true);
    401      1.1  mrg }
    402      1.1  mrg 
    403      1.1  mrg HwasanChunkView FindHeapChunkByAddress(uptr address) {
    404      1.1  mrg   if (!allocator.PointerIsMine(reinterpret_cast<void *>(address)))
    405      1.1  mrg     return HwasanChunkView();
    406      1.1  mrg   void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address));
    407      1.1  mrg   if (!block)
    408      1.1  mrg     return HwasanChunkView();
    409      1.1  mrg   Metadata *metadata =
    410      1.1  mrg       reinterpret_cast<Metadata*>(allocator.GetMetaData(block));
    411      1.1  mrg   return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
    412      1.1  mrg }
    413      1.1  mrg 
    414  1.1.1.2  mrg static const void *AllocationBegin(const void *p) {
    415  1.1.1.2  mrg   const void *untagged_ptr = UntagPtr(p);
    416  1.1.1.2  mrg   if (!untagged_ptr)
    417  1.1.1.2  mrg     return nullptr;
    418  1.1.1.2  mrg 
    419  1.1.1.2  mrg   const void *beg = allocator.GetBlockBegin(untagged_ptr);
    420  1.1.1.2  mrg   if (!beg)
    421  1.1.1.2  mrg     return nullptr;
    422  1.1.1.2  mrg 
    423  1.1.1.2  mrg   Metadata *b = (Metadata *)allocator.GetMetaData(beg);
    424  1.1.1.2  mrg   if (b->GetRequestedSize() == 0)
    425  1.1.1.2  mrg     return nullptr;
    426  1.1.1.2  mrg 
    427  1.1.1.2  mrg   tag_t tag = GetTagFromPointer((uptr)p);
    428  1.1.1.2  mrg   return (const void *)AddTagToPointer((uptr)beg, tag);
    429  1.1.1.2  mrg }
    430  1.1.1.2  mrg 
    431  1.1.1.2  mrg static uptr AllocationSize(const void *p) {
    432  1.1.1.2  mrg   const void *untagged_ptr = UntagPtr(p);
    433      1.1  mrg   if (!untagged_ptr) return 0;
    434      1.1  mrg   const void *beg = allocator.GetBlockBegin(untagged_ptr);
    435  1.1.1.2  mrg   if (!beg)
    436  1.1.1.2  mrg     return 0;
    437  1.1.1.2  mrg   Metadata *b = (Metadata *)allocator.GetMetaData(beg);
    438  1.1.1.2  mrg   return b->GetRequestedSize();
    439  1.1.1.2  mrg }
    440  1.1.1.2  mrg 
    441  1.1.1.2  mrg static uptr AllocationSizeFast(const void *p) {
    442  1.1.1.2  mrg   const void *untagged_ptr = UntagPtr(p);
    443  1.1.1.2  mrg   void *aligned_ptr = reinterpret_cast<void *>(
    444  1.1.1.2  mrg       RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
    445  1.1.1.2  mrg   Metadata *meta =
    446  1.1.1.2  mrg       reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
    447  1.1.1.2  mrg   return meta->GetRequestedSize();
    448      1.1  mrg }
    449      1.1  mrg 
    450      1.1  mrg void *hwasan_malloc(uptr size, StackTrace *stack) {
    451      1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
    452      1.1  mrg }
    453      1.1  mrg 
    454      1.1  mrg void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
    455      1.1  mrg   return SetErrnoOnNull(HwasanCalloc(stack, nmemb, size));
    456      1.1  mrg }
    457      1.1  mrg 
    458      1.1  mrg void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
    459      1.1  mrg   if (!ptr)
    460      1.1  mrg     return SetErrnoOnNull(HwasanAllocate(stack, size, sizeof(u64), false));
    461      1.1  mrg   if (size == 0) {
    462      1.1  mrg     HwasanDeallocate(stack, ptr);
    463      1.1  mrg     return nullptr;
    464      1.1  mrg   }
    465      1.1  mrg   return SetErrnoOnNull(HwasanReallocate(stack, ptr, size, sizeof(u64)));
    466      1.1  mrg }
    467      1.1  mrg 
    468      1.1  mrg void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack) {
    469      1.1  mrg   if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
    470      1.1  mrg     errno = errno_ENOMEM;
    471      1.1  mrg     if (AllocatorMayReturnNull())
    472      1.1  mrg       return nullptr;
    473      1.1  mrg     ReportReallocArrayOverflow(nmemb, size, stack);
    474      1.1  mrg   }
    475      1.1  mrg   return hwasan_realloc(ptr, nmemb * size, stack);
    476      1.1  mrg }
    477      1.1  mrg 
    478      1.1  mrg void *hwasan_valloc(uptr size, StackTrace *stack) {
    479      1.1  mrg   return SetErrnoOnNull(
    480      1.1  mrg       HwasanAllocate(stack, size, GetPageSizeCached(), false));
    481      1.1  mrg }
    482      1.1  mrg 
    483      1.1  mrg void *hwasan_pvalloc(uptr size, StackTrace *stack) {
    484      1.1  mrg   uptr PageSize = GetPageSizeCached();
    485      1.1  mrg   if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
    486      1.1  mrg     errno = errno_ENOMEM;
    487      1.1  mrg     if (AllocatorMayReturnNull())
    488      1.1  mrg       return nullptr;
    489      1.1  mrg     ReportPvallocOverflow(size, stack);
    490      1.1  mrg   }
    491      1.1  mrg   // pvalloc(0) should allocate one page.
    492      1.1  mrg   size = size ? RoundUpTo(size, PageSize) : PageSize;
    493      1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, PageSize, false));
    494      1.1  mrg }
    495      1.1  mrg 
    496      1.1  mrg void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
    497      1.1  mrg   if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
    498      1.1  mrg     errno = errno_EINVAL;
    499      1.1  mrg     if (AllocatorMayReturnNull())
    500      1.1  mrg       return nullptr;
    501      1.1  mrg     ReportInvalidAlignedAllocAlignment(size, alignment, stack);
    502      1.1  mrg   }
    503      1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
    504      1.1  mrg }
    505      1.1  mrg 
    506      1.1  mrg void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
    507      1.1  mrg   if (UNLIKELY(!IsPowerOfTwo(alignment))) {
    508      1.1  mrg     errno = errno_EINVAL;
    509      1.1  mrg     if (AllocatorMayReturnNull())
    510      1.1  mrg       return nullptr;
    511      1.1  mrg     ReportInvalidAllocationAlignment(alignment, stack);
    512      1.1  mrg   }
    513      1.1  mrg   return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
    514      1.1  mrg }
    515      1.1  mrg 
    516      1.1  mrg int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
    517      1.1  mrg                         StackTrace *stack) {
    518      1.1  mrg   if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
    519      1.1  mrg     if (AllocatorMayReturnNull())
    520      1.1  mrg       return errno_EINVAL;
    521      1.1  mrg     ReportInvalidPosixMemalignAlignment(alignment, stack);
    522      1.1  mrg   }
    523      1.1  mrg   void *ptr = HwasanAllocate(stack, size, alignment, false);
    524      1.1  mrg   if (UNLIKELY(!ptr))
    525      1.1  mrg     // OOM error is already taken care of by HwasanAllocate.
    526      1.1  mrg     return errno_ENOMEM;
    527      1.1  mrg   CHECK(IsAligned((uptr)ptr, alignment));
    528      1.1  mrg   *memptr = ptr;
    529      1.1  mrg   return 0;
    530      1.1  mrg }
    531      1.1  mrg 
    532      1.1  mrg void hwasan_free(void *ptr, StackTrace *stack) {
    533      1.1  mrg   return HwasanDeallocate(stack, ptr);
    534      1.1  mrg }
    535      1.1  mrg 
    536      1.1  mrg }  // namespace __hwasan
    537      1.1  mrg 
    538  1.1.1.2  mrg // --- Implementation of LSan-specific functions --- {{{1
    539  1.1.1.2  mrg namespace __lsan {
    540  1.1.1.2  mrg 
    541  1.1.1.2  mrg void LockAllocator() {
    542  1.1.1.2  mrg   __hwasan::HwasanAllocatorLock();
    543  1.1.1.2  mrg }
    544  1.1.1.2  mrg 
    545  1.1.1.2  mrg void UnlockAllocator() {
    546  1.1.1.2  mrg   __hwasan::HwasanAllocatorUnlock();
    547  1.1.1.2  mrg }
    548  1.1.1.2  mrg 
    549  1.1.1.2  mrg void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
    550  1.1.1.2  mrg   *begin = (uptr)&__hwasan::allocator;
    551  1.1.1.2  mrg   *end = *begin + sizeof(__hwasan::allocator);
    552  1.1.1.2  mrg }
    553  1.1.1.2  mrg 
    554  1.1.1.2  mrg uptr PointsIntoChunk(void *p) {
    555  1.1.1.2  mrg   p = UntagPtr(p);
    556  1.1.1.2  mrg   uptr addr = reinterpret_cast<uptr>(p);
    557  1.1.1.2  mrg   uptr chunk =
    558  1.1.1.2  mrg       reinterpret_cast<uptr>(__hwasan::allocator.GetBlockBeginFastLocked(p));
    559  1.1.1.2  mrg   if (!chunk)
    560  1.1.1.2  mrg     return 0;
    561  1.1.1.2  mrg   __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
    562  1.1.1.2  mrg       __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk)));
    563  1.1.1.2  mrg   if (!metadata || !metadata->IsAllocated())
    564  1.1.1.2  mrg     return 0;
    565  1.1.1.2  mrg   if (addr < chunk + metadata->GetRequestedSize())
    566  1.1.1.2  mrg     return chunk;
    567  1.1.1.2  mrg   if (IsSpecialCaseOfOperatorNew0(chunk, metadata->GetRequestedSize(), addr))
    568  1.1.1.2  mrg     return chunk;
    569  1.1.1.2  mrg   return 0;
    570  1.1.1.2  mrg }
    571  1.1.1.2  mrg 
    572  1.1.1.2  mrg uptr GetUserBegin(uptr chunk) {
    573  1.1.1.2  mrg   CHECK_EQ(UntagAddr(chunk), chunk);
    574  1.1.1.2  mrg   void *block = __hwasan::allocator.GetBlockBeginFastLocked(
    575  1.1.1.2  mrg       reinterpret_cast<void *>(chunk));
    576  1.1.1.2  mrg   if (!block)
    577  1.1.1.2  mrg     return 0;
    578  1.1.1.2  mrg   __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
    579  1.1.1.2  mrg       __hwasan::allocator.GetMetaData(block));
    580  1.1.1.2  mrg   if (!metadata || !metadata->IsAllocated())
    581  1.1.1.2  mrg     return 0;
    582  1.1.1.2  mrg 
    583  1.1.1.2  mrg   return reinterpret_cast<uptr>(block);
    584  1.1.1.2  mrg }
    585  1.1.1.2  mrg 
    586  1.1.1.2  mrg uptr GetUserAddr(uptr chunk) {
    587  1.1.1.2  mrg   if (!InTaggableRegion(chunk))
    588  1.1.1.2  mrg     return chunk;
    589  1.1.1.2  mrg   tag_t mem_tag = *(tag_t *)__hwasan::MemToShadow(chunk);
    590  1.1.1.2  mrg   return AddTagToPointer(chunk, mem_tag);
    591  1.1.1.2  mrg }
    592  1.1.1.2  mrg 
    593  1.1.1.2  mrg LsanMetadata::LsanMetadata(uptr chunk) {
    594  1.1.1.2  mrg   CHECK_EQ(UntagAddr(chunk), chunk);
    595  1.1.1.2  mrg   metadata_ =
    596  1.1.1.2  mrg       chunk ? __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk))
    597  1.1.1.2  mrg             : nullptr;
    598  1.1.1.2  mrg }
    599  1.1.1.2  mrg 
    600  1.1.1.2  mrg bool LsanMetadata::allocated() const {
    601  1.1.1.2  mrg   if (!metadata_)
    602  1.1.1.2  mrg     return false;
    603  1.1.1.2  mrg   __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
    604  1.1.1.2  mrg   return m->IsAllocated();
    605  1.1.1.2  mrg }
    606  1.1.1.2  mrg 
    607  1.1.1.2  mrg ChunkTag LsanMetadata::tag() const {
    608  1.1.1.2  mrg   __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
    609  1.1.1.2  mrg   return m->GetLsanTag();
    610  1.1.1.2  mrg }
    611  1.1.1.2  mrg 
    612  1.1.1.2  mrg void LsanMetadata::set_tag(ChunkTag value) {
    613  1.1.1.2  mrg   __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
    614  1.1.1.2  mrg   m->SetLsanTag(value);
    615  1.1.1.2  mrg }
    616  1.1.1.2  mrg 
    617  1.1.1.2  mrg uptr LsanMetadata::requested_size() const {
    618  1.1.1.2  mrg   __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
    619  1.1.1.2  mrg   return m->GetRequestedSize();
    620  1.1.1.2  mrg }
    621  1.1.1.2  mrg 
    622  1.1.1.2  mrg u32 LsanMetadata::stack_trace_id() const {
    623  1.1.1.2  mrg   __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
    624  1.1.1.2  mrg   return m->GetAllocStackId();
    625  1.1.1.2  mrg }
    626  1.1.1.2  mrg 
    627  1.1.1.2  mrg void ForEachChunk(ForEachChunkCallback callback, void *arg) {
    628  1.1.1.2  mrg   __hwasan::allocator.ForEachChunk(callback, arg);
    629  1.1.1.2  mrg }
    630  1.1.1.2  mrg 
    631  1.1.1.2  mrg IgnoreObjectResult IgnoreObject(const void *p) {
    632  1.1.1.2  mrg   p = UntagPtr(p);
    633  1.1.1.2  mrg   uptr addr = reinterpret_cast<uptr>(p);
    634  1.1.1.2  mrg   uptr chunk = reinterpret_cast<uptr>(__hwasan::allocator.GetBlockBegin(p));
    635  1.1.1.2  mrg   if (!chunk)
    636  1.1.1.2  mrg     return kIgnoreObjectInvalid;
    637  1.1.1.2  mrg   __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
    638  1.1.1.2  mrg       __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk)));
    639  1.1.1.2  mrg   if (!metadata || !metadata->IsAllocated())
    640  1.1.1.2  mrg     return kIgnoreObjectInvalid;
    641  1.1.1.2  mrg   if (addr >= chunk + metadata->GetRequestedSize())
    642  1.1.1.2  mrg     return kIgnoreObjectInvalid;
    643  1.1.1.2  mrg   if (metadata->GetLsanTag() == kIgnored)
    644  1.1.1.2  mrg     return kIgnoreObjectAlreadyIgnored;
    645  1.1.1.2  mrg 
    646  1.1.1.2  mrg   metadata->SetLsanTag(kIgnored);
    647  1.1.1.2  mrg   return kIgnoreObjectSuccess;
    648  1.1.1.2  mrg }
    649  1.1.1.2  mrg 
    650  1.1.1.2  mrg }  // namespace __lsan
    651  1.1.1.2  mrg 
    652      1.1  mrg using namespace __hwasan;
    653      1.1  mrg 
    654      1.1  mrg void __hwasan_enable_allocator_tagging() {
    655      1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 1);
    656      1.1  mrg }
    657      1.1  mrg 
    658      1.1  mrg void __hwasan_disable_allocator_tagging() {
    659      1.1  mrg   atomic_store_relaxed(&hwasan_allocator_tagging_enabled, 0);
    660      1.1  mrg }
    661      1.1  mrg 
    662      1.1  mrg uptr __sanitizer_get_current_allocated_bytes() {
    663      1.1  mrg   uptr stats[AllocatorStatCount];
    664      1.1  mrg   allocator.GetStats(stats);
    665      1.1  mrg   return stats[AllocatorStatAllocated];
    666      1.1  mrg }
    667      1.1  mrg 
    668      1.1  mrg uptr __sanitizer_get_heap_size() {
    669      1.1  mrg   uptr stats[AllocatorStatCount];
    670      1.1  mrg   allocator.GetStats(stats);
    671      1.1  mrg   return stats[AllocatorStatMapped];
    672      1.1  mrg }
    673      1.1  mrg 
    674      1.1  mrg uptr __sanitizer_get_free_bytes() { return 1; }
    675      1.1  mrg 
    676      1.1  mrg uptr __sanitizer_get_unmapped_bytes() { return 1; }
    677      1.1  mrg 
    678      1.1  mrg uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
    679      1.1  mrg 
    680      1.1  mrg int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
    681      1.1  mrg 
    682  1.1.1.2  mrg const void *__sanitizer_get_allocated_begin(const void *p) {
    683  1.1.1.2  mrg   return AllocationBegin(p);
    684  1.1.1.2  mrg }
    685  1.1.1.2  mrg 
    686      1.1  mrg uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
    687  1.1.1.2  mrg 
    688  1.1.1.2  mrg uptr __sanitizer_get_allocated_size_fast(const void *p) {
    689  1.1.1.2  mrg   DCHECK_EQ(p, __sanitizer_get_allocated_begin(p));
    690  1.1.1.2  mrg   uptr ret = AllocationSizeFast(p);
    691  1.1.1.2  mrg   DCHECK_EQ(ret, __sanitizer_get_allocated_size(p));
    692  1.1.1.2  mrg   return ret;
    693  1.1.1.2  mrg }
    694  1.1.1.2  mrg 
    695  1.1.1.2  mrg void __sanitizer_purge_allocator() { allocator.ForceReleaseToOS(); }
    696