1343175Sdim//===-- hwasan_checks.h -----------------------------------------*- C++ -*-===// 2343175Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343175Sdim// 7343175Sdim//===----------------------------------------------------------------------===// 8343175Sdim// 9343175Sdim// This file is a part of HWAddressSanitizer. 10343175Sdim// 11343175Sdim//===----------------------------------------------------------------------===// 12343175Sdim 13343175Sdim#ifndef HWASAN_CHECKS_H 14343175Sdim#define HWASAN_CHECKS_H 15343175Sdim 16343175Sdim#include "hwasan_mapping.h" 17353358Sdim#include "sanitizer_common/sanitizer_common.h" 18343175Sdim 19343175Sdimnamespace __hwasan { 20343175Sdimtemplate <unsigned X> 21343175Sdim__attribute__((always_inline)) static void SigTrap(uptr p) { 22343175Sdim#if defined(__aarch64__) 23343175Sdim (void)p; 24343175Sdim // 0x900 is added to do not interfere with the kernel use of lower values of 25343175Sdim // brk immediate. 26353358Sdim register uptr x0 asm("x0") = p; 27353358Sdim asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X)); 28343175Sdim#elif defined(__x86_64__) 29343175Sdim // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes 30343175Sdim // total. The pointer is passed via rdi. 31343175Sdim // 0x40 is added as a safeguard, to help distinguish our trap from others and 32343175Sdim // to avoid 0 offsets in the command (otherwise it'll be reduced to a 33343175Sdim // different nop command, the three bytes one). 34343175Sdim asm volatile( 35343175Sdim "int3\n" 36343175Sdim "nopl %c0(%%rax)\n" ::"n"(0x40 + X), 37343175Sdim "D"(p)); 38343175Sdim#else 39343175Sdim // FIXME: not always sigill. 40343175Sdim __builtin_trap(); 41343175Sdim#endif 42343175Sdim // __builtin_unreachable(); 43343175Sdim} 44343175Sdim 45353358Sdim// Version with access size which is not power of 2 46353358Sdimtemplate <unsigned X> 47353358Sdim__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) { 48353358Sdim#if defined(__aarch64__) 49353358Sdim register uptr x0 asm("x0") = p; 50353358Sdim register uptr x1 asm("x1") = size; 51353358Sdim asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X)); 52353358Sdim#elif defined(__x86_64__) 53353358Sdim // Size is stored in rsi. 54353358Sdim asm volatile( 55353358Sdim "int3\n" 56353358Sdim "nopl %c0(%%rax)\n" ::"n"(0x40 + X), 57353358Sdim "D"(p), "S"(size)); 58353358Sdim#else 59353358Sdim __builtin_trap(); 60353358Sdim#endif 61353358Sdim // __builtin_unreachable(); 62353358Sdim} 63353358Sdim 64353358Sdim__attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches( 65353358Sdim tag_t mem_tag, uptr ptr, uptr sz) { 66353358Sdim tag_t ptr_tag = GetTagFromPointer(ptr); 67353358Sdim if (ptr_tag == mem_tag) 68353358Sdim return true; 69353358Sdim if (mem_tag >= kShadowAlignment) 70353358Sdim return false; 71353358Sdim if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag) 72353358Sdim return false; 73353358Sdim#ifndef __aarch64__ 74353358Sdim ptr = UntagAddr(ptr); 75353358Sdim#endif 76353358Sdim return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag; 77353358Sdim} 78353358Sdim 79343175Sdimenum class ErrorAction { Abort, Recover }; 80343175Sdimenum class AccessType { Load, Store }; 81343175Sdim 82343175Sdimtemplate <ErrorAction EA, AccessType AT, unsigned LogSize> 83343175Sdim__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) { 84343175Sdim uptr ptr_raw = p & ~kAddressTagMask; 85343175Sdim tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw); 86353358Sdim if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) { 87343175Sdim SigTrap<0x20 * (EA == ErrorAction::Recover) + 88343175Sdim 0x10 * (AT == AccessType::Store) + LogSize>(p); 89343175Sdim if (EA == ErrorAction::Abort) 90343175Sdim __builtin_unreachable(); 91343175Sdim } 92343175Sdim} 93343175Sdim 94343175Sdimtemplate <ErrorAction EA, AccessType AT> 95343175Sdim__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p, 96343175Sdim uptr sz) { 97343175Sdim if (sz == 0) 98343175Sdim return; 99343175Sdim tag_t ptr_tag = GetTagFromPointer(p); 100343175Sdim uptr ptr_raw = p & ~kAddressTagMask; 101343175Sdim tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw); 102353358Sdim tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz); 103353358Sdim for (tag_t *t = shadow_first; t < shadow_last; ++t) 104343175Sdim if (UNLIKELY(ptr_tag != *t)) { 105343175Sdim SigTrap<0x20 * (EA == ErrorAction::Recover) + 106353358Sdim 0x10 * (AT == AccessType::Store) + 0xf>(p, sz); 107343175Sdim if (EA == ErrorAction::Abort) 108343175Sdim __builtin_unreachable(); 109343175Sdim } 110353358Sdim uptr end = p + sz; 111353358Sdim uptr tail_sz = end & 0xf; 112353358Sdim if (UNLIKELY(tail_sz != 0 && 113353358Sdim !PossiblyShortTagMatches( 114353358Sdim *shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) { 115353358Sdim SigTrap<0x20 * (EA == ErrorAction::Recover) + 116353358Sdim 0x10 * (AT == AccessType::Store) + 0xf>(p, sz); 117353358Sdim if (EA == ErrorAction::Abort) 118353358Sdim __builtin_unreachable(); 119353358Sdim } 120343175Sdim} 121353358Sdim 122343175Sdim} // end namespace __hwasan 123343175Sdim 124343175Sdim#endif // HWASAN_CHECKS_H 125