Path: blob/main/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan.h
35235 views
//===-- hwasan.h ------------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of HWAddressSanitizer.9//10// Private Hwasan header.11//===----------------------------------------------------------------------===//1213#ifndef HWASAN_H14#define HWASAN_H1516#include "hwasan_flags.h"17#include "hwasan_interface_internal.h"18#include "hwasan_mapping.h"19#include "sanitizer_common/sanitizer_common.h"20#include "sanitizer_common/sanitizer_flags.h"21#include "sanitizer_common/sanitizer_internal_defs.h"22#include "sanitizer_common/sanitizer_stacktrace.h"23#include "ubsan/ubsan_platform.h"2425#ifndef HWASAN_CONTAINS_UBSAN26# define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB27#endif2829#ifndef HWASAN_WITH_INTERCEPTORS30#define HWASAN_WITH_INTERCEPTORS 031#endif3233#ifndef HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE34#define HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE HWASAN_WITH_INTERCEPTORS35#endif3637typedef u8 tag_t;3839#if defined(HWASAN_ALIASING_MODE)40# if !defined(__x86_64__)41# error Aliasing mode is only supported on x86_6442# endif43// Tags are done in middle bits using userspace aliasing.44constexpr unsigned kAddressTagShift = 39;45constexpr unsigned kTagBits = 3;4647// The alias region is placed next to the shadow so the upper bits of all48// taggable addresses matches the upper bits of the shadow base. This shift49// value determines which upper bits must match. It has a floor of 44 since the50// shadow is always 8TB.51// TODO(morehouse): In alias mode we can shrink the shadow and use a52// simpler/faster shadow calculation.53constexpr unsigned kTaggableRegionCheckShift =54__sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);55#elif defined(__x86_64__)56// Tags are done in upper bits using Intel LAM.57constexpr unsigned kAddressTagShift = 57;58constexpr unsigned kTagBits = 6;59#else60// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address61// translation and can be used to store a tag.62constexpr unsigned kAddressTagShift = 56;63constexpr unsigned kTagBits = 8;64#endif // defined(HWASAN_ALIASING_MODE)6566// Mask for extracting tag bits from the lower 8 bits.67constexpr uptr kTagMask = (1UL << kTagBits) - 1;6869// Mask for extracting tag bits from full pointers.70constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;7172// Minimal alignment of the shadow base address. Determines the space available73// for threads and stack histories. This is an ABI constant.74const unsigned kShadowBaseAlignment = 32;7576const unsigned kRecordAddrBaseTagShift = 3;77const unsigned kRecordFPShift = 48;78const unsigned kRecordFPLShift = 4;79const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);8081static inline bool InTaggableRegion(uptr addr) {82#if defined(HWASAN_ALIASING_MODE)83// Aliases are mapped next to shadow so that the upper bits match the shadow84// base.85return (addr >> kTaggableRegionCheckShift) ==86(__hwasan::GetShadowOffset() >> kTaggableRegionCheckShift);87#endif88return true;89}9091static inline tag_t GetTagFromPointer(uptr p) {92return InTaggableRegion(p) ? ((p >> kAddressTagShift) & kTagMask) : 0;93}9495static inline uptr UntagAddr(uptr tagged_addr) {96return InTaggableRegion(tagged_addr) ? (tagged_addr & ~kAddressTagMask)97: tagged_addr;98}99100static inline void *UntagPtr(const void *tagged_ptr) {101return reinterpret_cast<void *>(102UntagAddr(reinterpret_cast<uptr>(tagged_ptr)));103}104105static inline uptr AddTagToPointer(uptr p, tag_t tag) {106return InTaggableRegion(p) ? ((p & ~kAddressTagMask) |107((uptr)(tag & kTagMask) << kAddressTagShift))108: p;109}110111namespace __hwasan {112113extern int hwasan_inited;114extern bool hwasan_init_is_running;115extern int hwasan_report_count;116117bool InitShadow();118void InitializeOsSupport();119void InitThreads();120void InitializeInterceptors();121122void HwasanAllocatorInit();123void HwasanAllocatorLock();124void HwasanAllocatorUnlock();125126void *hwasan_malloc(uptr size, StackTrace *stack);127void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack);128void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack);129void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack);130void *hwasan_valloc(uptr size, StackTrace *stack);131void *hwasan_pvalloc(uptr size, StackTrace *stack);132void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack);133void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack);134int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,135StackTrace *stack);136void hwasan_free(void *ptr, StackTrace *stack);137138void InstallAtExitHandler();139140#define GET_MALLOC_STACK_TRACE \141BufferedStackTrace stack; \142if (hwasan_inited) \143stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \144nullptr, common_flags()->fast_unwind_on_malloc, \145common_flags()->malloc_context_size)146147#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp) \148BufferedStackTrace stack; \149if (hwasan_inited) \150stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)151152void HwasanTSDInit();153void HwasanTSDThreadInit();154void HwasanAtExit();155156void HwasanOnDeadlySignal(int signo, void *info, void *context);157158void HwasanInstallAtForkHandler();159160void InstallAtExitCheckLeaks();161162void UpdateMemoryUsage();163164void AppendToErrorMessageBuffer(const char *buffer);165166void AndroidTestTlsSlot();167168// This is a compiler-generated struct that can be shared between hwasan169// implementations.170struct AccessInfo {171uptr addr;172uptr size;173bool is_store;174bool is_load;175bool recover;176};177178// Given access info and frame information, unwind the stack and report the tag179// mismatch.180void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc,181uptr *registers_frame = nullptr);182183// This dispatches to HandleTagMismatch but sets up the AccessInfo, program184// counter, and frame pointer.185void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info,186uptr *registers_frame, size_t outsize);187188} // namespace __hwasan189190#if HWASAN_WITH_INTERCEPTORS191// For both bionic and glibc __sigset_t is an unsigned long.192typedef unsigned long __hw_sigset_t;193// Setjmp and longjmp implementations are platform specific, and hence the194// interception code is platform specific too.195# if defined(__aarch64__)196constexpr size_t kHwRegisterBufSize = 22;197# elif defined(__x86_64__)198constexpr size_t kHwRegisterBufSize = 8;199# elif SANITIZER_RISCV64200// saving PC, 12 int regs, sp, 12 fp regs201# ifndef __riscv_float_abi_soft202constexpr size_t kHwRegisterBufSize = 1 + 12 + 1 + 12;203# else204constexpr size_t kHwRegisterBufSize = 1 + 12 + 1;205# endif206# endif207typedef unsigned long long __hw_register_buf[kHwRegisterBufSize];208struct __hw_jmp_buf_struct {209// NOTE: The machine-dependent definition of `__sigsetjmp'210// assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that211// `__mask_was_saved' follows it. Do not move these members or add others212// before it.213//214// We add a __magic field to our struct to catch cases where libc's setjmp215// populated the jmp_buf instead of our interceptor.216__hw_register_buf __jmpbuf; // Calling environment.217unsigned __mask_was_saved : 1; // Saved the signal mask?218unsigned __magic : 31; // Used to distinguish __hw_jmp_buf from jmp_buf.219__hw_sigset_t __saved_mask; // Saved signal mask.220};221typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1];222typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1];223constexpr unsigned kHwJmpBufMagic = 0x248ACE77;224#endif // HWASAN_WITH_INTERCEPTORS225226#define ENSURE_HWASAN_INITED() \227do { \228CHECK(!hwasan_init_is_running); \229if (!hwasan_inited) { \230__hwasan_init(); \231} \232} while (0)233234#endif // HWASAN_H235236237