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