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