1//===-- hwasan.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// Private Hwasan header. 12//===----------------------------------------------------------------------===// 13 14#ifndef HWASAN_H 15#define HWASAN_H 16 17#include "hwasan_flags.h" 18#include "hwasan_interface_internal.h" 19#include "sanitizer_common/sanitizer_common.h" 20#include "sanitizer_common/sanitizer_flags.h" 21#include "sanitizer_common/sanitizer_internal_defs.h" 22#include "sanitizer_common/sanitizer_stacktrace.h" 23#include "ubsan/ubsan_platform.h" 24 25#ifndef HWASAN_CONTAINS_UBSAN 26# define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB 27#endif 28 29#ifndef HWASAN_WITH_INTERCEPTORS 30#define HWASAN_WITH_INTERCEPTORS 0 31#endif 32 33#ifndef HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE 34#define HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE HWASAN_WITH_INTERCEPTORS 35#endif 36 37typedef u8 tag_t; 38 39#if defined(HWASAN_ALIASING_MODE) 40# if !defined(__x86_64__) 41# error Aliasing mode is only supported on x86_64 42# endif 43// Tags are done in middle bits using userspace aliasing. 44constexpr unsigned kAddressTagShift = 39; 45constexpr unsigned kTagBits = 3; 46 47// The alias region is placed next to the shadow so the upper bits of all 48// taggable addresses matches the upper bits of the shadow base. This shift 49// value determines which upper bits must match. It has a floor of 44 since the 50// shadow is always 8TB. 51// TODO(morehouse): In alias mode we can shrink the shadow and use a 52// simpler/faster shadow calculation. 53constexpr unsigned kTaggableRegionCheckShift = 54 __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U); 55#elif defined(__x86_64__) 56// Tags are done in upper bits using Intel LAM. 57constexpr unsigned kAddressTagShift = 57; 58constexpr unsigned kTagBits = 6; 59#else 60// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address 61// translation and can be used to store a tag. 62constexpr unsigned kAddressTagShift = 56; 63constexpr unsigned kTagBits = 8; 64#endif // defined(HWASAN_ALIASING_MODE) 65 66// Mask for extracting tag bits from the lower 8 bits. 67constexpr uptr kTagMask = (1UL << kTagBits) - 1; 68 69// Mask for extracting tag bits from full pointers. 70constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift; 71 72// Minimal alignment of the shadow base address. Determines the space available 73// for threads and stack histories. This is an ABI constant. 74const unsigned kShadowBaseAlignment = 32; 75 76const unsigned kRecordAddrBaseTagShift = 3; 77const unsigned kRecordFPShift = 48; 78const unsigned kRecordFPLShift = 4; 79const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift); 80 81static inline tag_t GetTagFromPointer(uptr p) { 82 return (p >> kAddressTagShift) & kTagMask; 83} 84 85static inline uptr UntagAddr(uptr tagged_addr) { 86 return tagged_addr & ~kAddressTagMask; 87} 88 89static inline void *UntagPtr(const void *tagged_ptr) { 90 return reinterpret_cast<void *>( 91 UntagAddr(reinterpret_cast<uptr>(tagged_ptr))); 92} 93 94static inline uptr AddTagToPointer(uptr p, tag_t tag) { 95 return (p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift); 96} 97 98namespace __hwasan { 99 100extern int hwasan_inited; 101extern bool hwasan_init_is_running; 102extern int hwasan_report_count; 103 104bool InitShadow(); 105void InitializeOsSupport(); 106void InitThreads(); 107void InitializeInterceptors(); 108 109void HwasanAllocatorInit(); 110void HwasanAllocatorLock(); 111void HwasanAllocatorUnlock(); 112 113void *hwasan_malloc(uptr size, StackTrace *stack); 114void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); 115void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack); 116void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack); 117void *hwasan_valloc(uptr size, StackTrace *stack); 118void *hwasan_pvalloc(uptr size, StackTrace *stack); 119void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); 120void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack); 121int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size, 122 StackTrace *stack); 123void hwasan_free(void *ptr, StackTrace *stack); 124 125void InstallAtExitHandler(); 126 127#define GET_MALLOC_STACK_TRACE \ 128 BufferedStackTrace stack; \ 129 if (hwasan_inited) \ 130 stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \ 131 nullptr, common_flags()->fast_unwind_on_malloc, \ 132 common_flags()->malloc_context_size) 133 134#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \ 135 BufferedStackTrace stack; \ 136 if (hwasan_inited) \ 137 stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal) 138 139void HwasanTSDInit(); 140void HwasanTSDThreadInit(); 141void HwasanAtExit(); 142 143void HwasanOnDeadlySignal(int signo, void *info, void *context); 144 145void HwasanInstallAtForkHandler(); 146 147void UpdateMemoryUsage(); 148 149void AppendToErrorMessageBuffer(const char *buffer); 150 151void AndroidTestTlsSlot(); 152 153// This is a compiler-generated struct that can be shared between hwasan 154// implementations. 155struct AccessInfo { 156 uptr addr; 157 uptr size; 158 bool is_store; 159 bool is_load; 160 bool recover; 161}; 162 163// Given access info and frame information, unwind the stack and report the tag 164// mismatch. 165void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc, 166 uptr *registers_frame = nullptr); 167 168// This dispatches to HandleTagMismatch but sets up the AccessInfo, program 169// counter, and frame pointer. 170void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame, 171 size_t outsize); 172 173} // namespace __hwasan 174 175#define HWASAN_MALLOC_HOOK(ptr, size) \ 176 do { \ 177 if (&__sanitizer_malloc_hook) { \ 178 __sanitizer_malloc_hook(ptr, size); \ 179 } \ 180 RunMallocHooks(ptr, size); \ 181 } while (false) 182#define HWASAN_FREE_HOOK(ptr) \ 183 do { \ 184 if (&__sanitizer_free_hook) { \ 185 __sanitizer_free_hook(ptr); \ 186 } \ 187 RunFreeHooks(ptr); \ 188 } while (false) 189 190#if HWASAN_WITH_INTERCEPTORS 191// For both bionic and glibc __sigset_t is an unsigned long. 192typedef unsigned long __hw_sigset_t; 193// Setjmp and longjmp implementations are platform specific, and hence the 194// interception code is platform specific too. 195# if defined(__aarch64__) 196constexpr size_t kHwRegisterBufSize = 22; 197# elif defined(__x86_64__) 198constexpr size_t kHwRegisterBufSize = 8; 199# endif 200typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; 201struct __hw_jmp_buf_struct { 202 // NOTE: The machine-dependent definition of `__sigsetjmp' 203 // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that 204 // `__mask_was_saved' follows it. Do not move these members or add others 205 // before it. 206 // 207 // We add a __magic field to our struct to catch cases where libc's setjmp 208 // populated the jmp_buf instead of our interceptor. 209 __hw_register_buf __jmpbuf; // Calling environment. 210 unsigned __mask_was_saved : 1; // Saved the signal mask? 211 unsigned __magic : 31; // Used to distinguish __hw_jmp_buf from jmp_buf. 212 __hw_sigset_t __saved_mask; // Saved signal mask. 213}; 214typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1]; 215typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1]; 216constexpr unsigned kHwJmpBufMagic = 0x248ACE77; 217#endif // HWASAN_WITH_INTERCEPTORS 218 219#define ENSURE_HWASAN_INITED() \ 220 do { \ 221 CHECK(!hwasan_init_is_running); \ 222 if (!hwasan_inited) { \ 223 __hwasan_init(); \ 224 } \ 225 } while (0) 226 227#endif // HWASAN_H 228