1 //===-- hwasan_checks.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 //===----------------------------------------------------------------------===// 12 13 #ifndef HWASAN_CHECKS_H 14 #define HWASAN_CHECKS_H 15 16 #include "hwasan_mapping.h" 17 #include "sanitizer_common/sanitizer_common.h" 18 19 namespace __hwasan { 20 template <unsigned X> 21 __attribute__((always_inline)) static void SigTrap(uptr p) { 22 #if defined(__aarch64__) 23 (void)p; 24 // 0x900 is added to do not interfere with the kernel use of lower values of 25 // brk immediate. 26 register uptr x0 asm("x0") = p; 27 asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X)); 28 #elif defined(__x86_64__) 29 // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes 30 // total. The pointer is passed via rdi. 31 // 0x40 is added as a safeguard, to help distinguish our trap from others and 32 // to avoid 0 offsets in the command (otherwise it'll be reduced to a 33 // different nop command, the three bytes one). 34 asm volatile( 35 "int3\n" 36 "nopl %c0(%%rax)\n" ::"n"(0x40 + X), 37 "D"(p)); 38 #else 39 // FIXME: not always sigill. 40 __builtin_trap(); 41 #endif 42 // __builtin_unreachable(); 43 } 44 45 // Version with access size which is not power of 2 46 template <unsigned X> 47 __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) { 48 #if defined(__aarch64__) 49 register uptr x0 asm("x0") = p; 50 register uptr x1 asm("x1") = size; 51 asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X)); 52 #elif defined(__x86_64__) 53 // Size is stored in rsi. 54 asm volatile( 55 "int3\n" 56 "nopl %c0(%%rax)\n" ::"n"(0x40 + X), 57 "D"(p), "S"(size)); 58 #else 59 __builtin_trap(); 60 #endif 61 // __builtin_unreachable(); 62 } 63 64 __attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches( 65 tag_t mem_tag, uptr ptr, uptr sz) { 66 tag_t ptr_tag = GetTagFromPointer(ptr); 67 if (ptr_tag == mem_tag) 68 return true; 69 if (mem_tag >= kShadowAlignment) 70 return false; 71 if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag) 72 return false; 73 #ifndef __aarch64__ 74 ptr = UntagAddr(ptr); 75 #endif 76 return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag; 77 } 78 79 enum class ErrorAction { Abort, Recover }; 80 enum class AccessType { Load, Store }; 81 82 template <ErrorAction EA, AccessType AT, unsigned LogSize> 83 __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) { 84 uptr ptr_raw = p & ~kAddressTagMask; 85 tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw); 86 if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) { 87 SigTrap<0x20 * (EA == ErrorAction::Recover) + 88 0x10 * (AT == AccessType::Store) + LogSize>(p); 89 if (EA == ErrorAction::Abort) 90 __builtin_unreachable(); 91 } 92 } 93 94 template <ErrorAction EA, AccessType AT> 95 __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p, 96 uptr sz) { 97 if (sz == 0) 98 return; 99 tag_t ptr_tag = GetTagFromPointer(p); 100 uptr ptr_raw = p & ~kAddressTagMask; 101 tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw); 102 tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz); 103 for (tag_t *t = shadow_first; t < shadow_last; ++t) 104 if (UNLIKELY(ptr_tag != *t)) { 105 SigTrap<0x20 * (EA == ErrorAction::Recover) + 106 0x10 * (AT == AccessType::Store) + 0xf>(p, sz); 107 if (EA == ErrorAction::Abort) 108 __builtin_unreachable(); 109 } 110 uptr end = p + sz; 111 uptr tail_sz = end & 0xf; 112 if (UNLIKELY(tail_sz != 0 && 113 !PossiblyShortTagMatches( 114 *shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) { 115 SigTrap<0x20 * (EA == ErrorAction::Recover) + 116 0x10 * (AT == AccessType::Store) + 0xf>(p, sz); 117 if (EA == ErrorAction::Abort) 118 __builtin_unreachable(); 119 } 120 } 121 122 } // end namespace __hwasan 123 124 #endif // HWASAN_CHECKS_H 125