(root)/
gcc-13.2.0/
libsanitizer/
hwasan/
hwasan_checks.h
       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  #elif SANITIZER_RISCV64
      40    // Put pointer into x10
      41    // addiw contains immediate of 0x40 + X, where 0x40 is magic number and X
      42    // encodes access size
      43    register uptr x10 asm("x10") = p;
      44    asm volatile(
      45        "ebreak\n"
      46        "addiw x0, x0, %1\n" ::"r"(x10),
      47        "I"(0x40 + X));
      48  #else
      49    // FIXME: not always sigill.
      50    __builtin_trap();
      51  #endif
      52    // __builtin_unreachable();
      53  }
      54  
      55  // Version with access size which is not power of 2
      56  template <unsigned X>
      57  __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
      58  #if defined(__aarch64__)
      59    register uptr x0 asm("x0") = p;
      60    register uptr x1 asm("x1") = size;
      61    asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
      62  #elif defined(__x86_64__)
      63    // Size is stored in rsi.
      64    asm volatile(
      65        "int3\n"
      66        "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
      67        "D"(p), "S"(size));
      68  #elif SANITIZER_RISCV64
      69    // Put access size into x11
      70    register uptr x10 asm("x10") = p;
      71    register uptr x11 asm("x11") = size;
      72    asm volatile(
      73        "ebreak\n"
      74        "addiw x0, x0, %2\n" ::"r"(x10),
      75        "r"(x11), "I"(0x40 + X));
      76  #else
      77    __builtin_trap();
      78  #endif
      79    // __builtin_unreachable();
      80  }
      81  
      82  __attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches(
      83      tag_t mem_tag, uptr ptr, uptr sz) {
      84    tag_t ptr_tag = GetTagFromPointer(ptr);
      85    if (ptr_tag == mem_tag)
      86      return true;
      87    if (mem_tag >= kShadowAlignment)
      88      return false;
      89    if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag)
      90      return false;
      91  #if !defined(__aarch64__) && !(SANITIZER_RISCV64)
      92    ptr = UntagAddr(ptr);
      93  #endif
      94    return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag;
      95  }
      96  
      97  enum class ErrorAction { Abort, Recover };
      98  enum class AccessType { Load, Store };
      99  
     100  template <ErrorAction EA, AccessType AT, unsigned LogSize>
     101  __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
     102    if (!InTaggableRegion(p))
     103      return;
     104    uptr ptr_raw = p & ~kAddressTagMask;
     105    tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
     106    if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
     107      SigTrap<0x20 * (EA == ErrorAction::Recover) +
     108              0x10 * (AT == AccessType::Store) + LogSize>(p);
     109      if (EA == ErrorAction::Abort)
     110        __builtin_unreachable();
     111    }
     112  }
     113  
     114  template <ErrorAction EA, AccessType AT>
     115  __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
     116                                                                        uptr sz) {
     117    if (sz == 0 || !InTaggableRegion(p))
     118      return;
     119    tag_t ptr_tag = GetTagFromPointer(p);
     120    uptr ptr_raw = p & ~kAddressTagMask;
     121    tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw);
     122    tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz);
     123    for (tag_t *t = shadow_first; t < shadow_last; ++t)
     124      if (UNLIKELY(ptr_tag != *t)) {
     125        SigTrap<0x20 * (EA == ErrorAction::Recover) +
     126                0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
     127        if (EA == ErrorAction::Abort)
     128          __builtin_unreachable();
     129      }
     130    uptr end = p + sz;
     131    uptr tail_sz = end & 0xf;
     132    if (UNLIKELY(tail_sz != 0 &&
     133                 !PossiblyShortTagMatches(
     134                     *shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) {
     135      SigTrap<0x20 * (EA == ErrorAction::Recover) +
     136              0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
     137      if (EA == ErrorAction::Abort)
     138        __builtin_unreachable();
     139    }
     140  }
     141  
     142  }  // end namespace __hwasan
     143  
     144  #endif  // HWASAN_CHECKS_H