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 37 typedef 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. 44 constexpr unsigned kAddressTagShift = 39; 45 constexpr 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. 53 constexpr unsigned kTaggableRegionCheckShift = 54 __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U); 55 #elif defined(__x86_64__) 56 // Tags are done in upper bits using Intel LAM. 57 constexpr unsigned kAddressTagShift = 57; 58 constexpr 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. 62 constexpr unsigned kAddressTagShift = 56; 63 constexpr unsigned kTagBits = 8; 64 #endif // defined(HWASAN_ALIASING_MODE) 65 66 // Mask for extracting tag bits from the lower 8 bits. 67 constexpr uptr kTagMask = (1UL << kTagBits) - 1; 68 69 // Mask for extracting tag bits from full pointers. 70 constexpr 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. 74 const unsigned kShadowBaseAlignment = 32; 75 76 const unsigned kRecordAddrBaseTagShift = 3; 77 const unsigned kRecordFPShift = 48; 78 const unsigned kRecordFPLShift = 4; 79 const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift); 80 81 static inline tag_t GetTagFromPointer(uptr p) { 82 return (p >> kAddressTagShift) & kTagMask; 83 } 84 85 static inline uptr UntagAddr(uptr tagged_addr) { 86 return tagged_addr & ~kAddressTagMask; 87 } 88 89 static inline void *UntagPtr(const void *tagged_ptr) { 90 return reinterpret_cast<void *>( 91 UntagAddr(reinterpret_cast<uptr>(tagged_ptr))); 92 } 93 94 static inline uptr AddTagToPointer(uptr p, tag_t tag) { 95 return (p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift); 96 } 97 98 namespace __hwasan { 99 100 extern int hwasan_inited; 101 extern bool hwasan_init_is_running; 102 extern int hwasan_report_count; 103 104 bool InitShadow(); 105 void InitializeOsSupport(); 106 void InitThreads(); 107 void InitializeInterceptors(); 108 109 void HwasanAllocatorInit(); 110 void HwasanAllocatorLock(); 111 void HwasanAllocatorUnlock(); 112 113 void *hwasan_malloc(uptr size, StackTrace *stack); 114 void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); 115 void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack); 116 void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack); 117 void *hwasan_valloc(uptr size, StackTrace *stack); 118 void *hwasan_pvalloc(uptr size, StackTrace *stack); 119 void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack); 120 void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack); 121 int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size, 122 StackTrace *stack); 123 void hwasan_free(void *ptr, StackTrace *stack); 124 125 void 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 139 void HwasanTSDInit(); 140 void HwasanTSDThreadInit(); 141 void HwasanAtExit(); 142 143 void HwasanOnDeadlySignal(int signo, void *info, void *context); 144 145 void HwasanInstallAtForkHandler(); 146 147 void InstallAtExitCheckLeaks(); 148 149 void UpdateMemoryUsage(); 150 151 void AppendToErrorMessageBuffer(const char *buffer); 152 153 void AndroidTestTlsSlot(); 154 155 // This is a compiler-generated struct that can be shared between hwasan 156 // implementations. 157 struct AccessInfo { 158 uptr addr; 159 uptr size; 160 bool is_store; 161 bool is_load; 162 bool recover; 163 }; 164 165 // Given access info and frame information, unwind the stack and report the tag 166 // mismatch. 167 void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc, 168 uptr *registers_frame = nullptr); 169 170 // This dispatches to HandleTagMismatch but sets up the AccessInfo, program 171 // counter, and frame pointer. 172 void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info, 173 uptr *registers_frame, size_t outsize); 174 175 } // namespace __hwasan 176 177 #if HWASAN_WITH_INTERCEPTORS 178 // For both bionic and glibc __sigset_t is an unsigned long. 179 typedef unsigned long __hw_sigset_t; 180 // Setjmp and longjmp implementations are platform specific, and hence the 181 // interception code is platform specific too. 182 # if defined(__aarch64__) 183 constexpr size_t kHwRegisterBufSize = 22; 184 # elif defined(__x86_64__) 185 constexpr size_t kHwRegisterBufSize = 8; 186 # elif SANITIZER_RISCV64 187 // saving PC, 12 int regs, sp, 12 fp regs 188 # ifndef __riscv_float_abi_soft 189 constexpr size_t kHwRegisterBufSize = 1 + 12 + 1 + 12; 190 # else 191 constexpr size_t kHwRegisterBufSize = 1 + 12 + 1; 192 # endif 193 # endif 194 typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; 195 struct __hw_jmp_buf_struct { 196 // NOTE: The machine-dependent definition of `__sigsetjmp' 197 // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that 198 // `__mask_was_saved' follows it. Do not move these members or add others 199 // before it. 200 // 201 // We add a __magic field to our struct to catch cases where libc's setjmp 202 // populated the jmp_buf instead of our interceptor. 203 __hw_register_buf __jmpbuf; // Calling environment. 204 unsigned __mask_was_saved : 1; // Saved the signal mask? 205 unsigned __magic : 31; // Used to distinguish __hw_jmp_buf from jmp_buf. 206 __hw_sigset_t __saved_mask; // Saved signal mask. 207 }; 208 typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1]; 209 typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1]; 210 constexpr unsigned kHwJmpBufMagic = 0x248ACE77; 211 #endif // HWASAN_WITH_INTERCEPTORS 212 213 #define ENSURE_HWASAN_INITED() \ 214 do { \ 215 CHECK(!hwasan_init_is_running); \ 216 if (!hwasan_inited) { \ 217 __hwasan_init(); \ 218 } \ 219 } while (0) 220 221 #endif // HWASAN_H 222