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