10b57cec5SDimitry Andric //===-- hwasan.h ------------------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file is a part of HWAddressSanitizer.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // Private Hwasan header.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #ifndef HWASAN_H
150b57cec5SDimitry Andric #define HWASAN_H
160b57cec5SDimitry Andric 
17fe6060f1SDimitry Andric #include "hwasan_flags.h"
18fe6060f1SDimitry Andric #include "hwasan_interface_internal.h"
1906c3fb27SDimitry Andric #include "hwasan_mapping.h"
20fe6060f1SDimitry Andric #include "sanitizer_common/sanitizer_common.h"
210b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
220b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
230b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
240b57cec5SDimitry Andric #include "ubsan/ubsan_platform.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #ifndef HWASAN_CONTAINS_UBSAN
270b57cec5SDimitry Andric # define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB
280b57cec5SDimitry Andric #endif
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #ifndef HWASAN_WITH_INTERCEPTORS
310b57cec5SDimitry Andric #define HWASAN_WITH_INTERCEPTORS 0
320b57cec5SDimitry Andric #endif
330b57cec5SDimitry Andric 
34e8d8bef9SDimitry Andric #ifndef HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE
35e8d8bef9SDimitry Andric #define HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE HWASAN_WITH_INTERCEPTORS
36e8d8bef9SDimitry Andric #endif
37e8d8bef9SDimitry Andric 
380b57cec5SDimitry Andric typedef u8 tag_t;
390b57cec5SDimitry Andric 
40fe6060f1SDimitry Andric #if defined(HWASAN_ALIASING_MODE)
41fe6060f1SDimitry Andric #  if !defined(__x86_64__)
42fe6060f1SDimitry Andric #    error Aliasing mode is only supported on x86_64
43fe6060f1SDimitry Andric #  endif
44fe6060f1SDimitry Andric // Tags are done in middle bits using userspace aliasing.
45fe6060f1SDimitry Andric constexpr unsigned kAddressTagShift = 39;
46fe6060f1SDimitry Andric constexpr unsigned kTagBits = 3;
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric // The alias region is placed next to the shadow so the upper bits of all
49fe6060f1SDimitry Andric // taggable addresses matches the upper bits of the shadow base.  This shift
50fe6060f1SDimitry Andric // value determines which upper bits must match.  It has a floor of 44 since the
51fe6060f1SDimitry Andric // shadow is always 8TB.
52fe6060f1SDimitry Andric // TODO(morehouse): In alias mode we can shrink the shadow and use a
53fe6060f1SDimitry Andric // simpler/faster shadow calculation.
54fe6060f1SDimitry Andric constexpr unsigned kTaggableRegionCheckShift =
55fe6060f1SDimitry Andric     __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
56fe6060f1SDimitry Andric #elif defined(__x86_64__)
57fe6060f1SDimitry Andric // Tags are done in upper bits using Intel LAM.
58fe6060f1SDimitry Andric constexpr unsigned kAddressTagShift = 57;
59fe6060f1SDimitry Andric constexpr unsigned kTagBits = 6;
60fe6060f1SDimitry Andric #else
610b57cec5SDimitry Andric // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
620b57cec5SDimitry Andric // translation and can be used to store a tag.
63fe6060f1SDimitry Andric constexpr unsigned kAddressTagShift = 56;
64fe6060f1SDimitry Andric constexpr unsigned kTagBits = 8;
65fe6060f1SDimitry Andric #endif  // defined(HWASAN_ALIASING_MODE)
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric // Mask for extracting tag bits from the lower 8 bits.
68fe6060f1SDimitry Andric constexpr uptr kTagMask = (1UL << kTagBits) - 1;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric // Mask for extracting tag bits from full pointers.
71fe6060f1SDimitry Andric constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric // Minimal alignment of the shadow base address. Determines the space available
740b57cec5SDimitry Andric // for threads and stack histories. This is an ABI constant.
750b57cec5SDimitry Andric const unsigned kShadowBaseAlignment = 32;
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric const unsigned kRecordAddrBaseTagShift = 3;
780b57cec5SDimitry Andric const unsigned kRecordFPShift = 48;
790b57cec5SDimitry Andric const unsigned kRecordFPLShift = 4;
800b57cec5SDimitry Andric const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
810b57cec5SDimitry Andric 
InTaggableRegion(uptr addr)8206c3fb27SDimitry Andric static inline bool InTaggableRegion(uptr addr) {
8306c3fb27SDimitry Andric #if defined(HWASAN_ALIASING_MODE)
8406c3fb27SDimitry Andric   // Aliases are mapped next to shadow so that the upper bits match the shadow
8506c3fb27SDimitry Andric   // base.
8606c3fb27SDimitry Andric   return (addr >> kTaggableRegionCheckShift) ==
8706c3fb27SDimitry Andric          (__hwasan::GetShadowOffset() >> kTaggableRegionCheckShift);
8806c3fb27SDimitry Andric #endif
8906c3fb27SDimitry Andric   return true;
9006c3fb27SDimitry Andric }
9106c3fb27SDimitry Andric 
GetTagFromPointer(uptr p)920b57cec5SDimitry Andric static inline tag_t GetTagFromPointer(uptr p) {
9306c3fb27SDimitry Andric   return InTaggableRegion(p) ? ((p >> kAddressTagShift) & kTagMask) : 0;
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric 
UntagAddr(uptr tagged_addr)960b57cec5SDimitry Andric static inline uptr UntagAddr(uptr tagged_addr) {
9706c3fb27SDimitry Andric   return InTaggableRegion(tagged_addr) ? (tagged_addr & ~kAddressTagMask)
9806c3fb27SDimitry Andric                                        : tagged_addr;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric 
UntagPtr(const void * tagged_ptr)1010b57cec5SDimitry Andric static inline void *UntagPtr(const void *tagged_ptr) {
1020b57cec5SDimitry Andric   return reinterpret_cast<void *>(
1030b57cec5SDimitry Andric       UntagAddr(reinterpret_cast<uptr>(tagged_ptr)));
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
AddTagToPointer(uptr p,tag_t tag)1060b57cec5SDimitry Andric static inline uptr AddTagToPointer(uptr p, tag_t tag) {
1075f757f3fSDimitry Andric   return InTaggableRegion(p) ? ((p & ~kAddressTagMask) |
1085f757f3fSDimitry Andric                                 ((uptr)(tag & kTagMask) << kAddressTagShift))
10906c3fb27SDimitry Andric                              : p;
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric namespace __hwasan {
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric extern int hwasan_inited;
1150b57cec5SDimitry Andric extern bool hwasan_init_is_running;
1160b57cec5SDimitry Andric extern int hwasan_report_count;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric bool InitShadow();
119fe6060f1SDimitry Andric void InitializeOsSupport();
1200b57cec5SDimitry Andric void InitThreads();
1210b57cec5SDimitry Andric void InitializeInterceptors();
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric void HwasanAllocatorInit();
124349cc55cSDimitry Andric void HwasanAllocatorLock();
125349cc55cSDimitry Andric void HwasanAllocatorUnlock();
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric void *hwasan_malloc(uptr size, StackTrace *stack);
1280b57cec5SDimitry Andric void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack);
1290b57cec5SDimitry Andric void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack);
1300b57cec5SDimitry Andric void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack);
1310b57cec5SDimitry Andric void *hwasan_valloc(uptr size, StackTrace *stack);
1320b57cec5SDimitry Andric void *hwasan_pvalloc(uptr size, StackTrace *stack);
1330b57cec5SDimitry Andric void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack);
1340b57cec5SDimitry Andric void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack);
1350b57cec5SDimitry Andric int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
1360b57cec5SDimitry Andric                         StackTrace *stack);
1370b57cec5SDimitry Andric void hwasan_free(void *ptr, StackTrace *stack);
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric void InstallAtExitHandler();
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric #define GET_MALLOC_STACK_TRACE                                            \
1420b57cec5SDimitry Andric   BufferedStackTrace stack;                                               \
1430b57cec5SDimitry Andric   if (hwasan_inited)                                                      \
1440b57cec5SDimitry Andric     stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \
1450b57cec5SDimitry Andric                  nullptr, common_flags()->fast_unwind_on_malloc,          \
1460b57cec5SDimitry Andric                  common_flags()->malloc_context_size)
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \
1490b57cec5SDimitry Andric   BufferedStackTrace stack;                              \
1500b57cec5SDimitry Andric   if (hwasan_inited)                                     \
1510b57cec5SDimitry Andric     stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric void HwasanTSDInit();
1540b57cec5SDimitry Andric void HwasanTSDThreadInit();
155fe6060f1SDimitry Andric void HwasanAtExit();
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric void HwasanOnDeadlySignal(int signo, void *info, void *context);
1580b57cec5SDimitry Andric 
159349cc55cSDimitry Andric void HwasanInstallAtForkHandler();
160349cc55cSDimitry Andric 
161bdd1243dSDimitry Andric void InstallAtExitCheckLeaks();
162bdd1243dSDimitry Andric 
1630b57cec5SDimitry Andric void UpdateMemoryUsage();
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric void AppendToErrorMessageBuffer(const char *buffer);
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric void AndroidTestTlsSlot();
1680b57cec5SDimitry Andric 
169fe6060f1SDimitry Andric // This is a compiler-generated struct that can be shared between hwasan
170fe6060f1SDimitry Andric // implementations.
171fe6060f1SDimitry Andric struct AccessInfo {
172fe6060f1SDimitry Andric   uptr addr;
173fe6060f1SDimitry Andric   uptr size;
174fe6060f1SDimitry Andric   bool is_store;
175fe6060f1SDimitry Andric   bool is_load;
176fe6060f1SDimitry Andric   bool recover;
177fe6060f1SDimitry Andric };
178fe6060f1SDimitry Andric 
179fe6060f1SDimitry Andric // Given access info and frame information, unwind the stack and report the tag
180fe6060f1SDimitry Andric // mismatch.
181fe6060f1SDimitry Andric void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc,
182fe6060f1SDimitry Andric                        uptr *registers_frame = nullptr);
183fe6060f1SDimitry Andric 
184fe6060f1SDimitry Andric // This dispatches to HandleTagMismatch but sets up the AccessInfo, program
185fe6060f1SDimitry Andric // counter, and frame pointer.
186bdd1243dSDimitry Andric void HwasanTagMismatch(uptr addr, uptr pc, uptr frame, uptr access_info,
187bdd1243dSDimitry Andric                        uptr *registers_frame, size_t outsize);
188fe6060f1SDimitry Andric 
1890b57cec5SDimitry Andric }  // namespace __hwasan
1900b57cec5SDimitry Andric 
191349cc55cSDimitry Andric #if HWASAN_WITH_INTERCEPTORS
192480093f4SDimitry Andric // For both bionic and glibc __sigset_t is an unsigned long.
193480093f4SDimitry Andric typedef unsigned long __hw_sigset_t;
194480093f4SDimitry Andric // Setjmp and longjmp implementations are platform specific, and hence the
195349cc55cSDimitry Andric // interception code is platform specific too.
196349cc55cSDimitry Andric #  if defined(__aarch64__)
197349cc55cSDimitry Andric constexpr size_t kHwRegisterBufSize = 22;
198349cc55cSDimitry Andric #  elif defined(__x86_64__)
199349cc55cSDimitry Andric constexpr size_t kHwRegisterBufSize = 8;
200bdd1243dSDimitry Andric #  elif SANITIZER_RISCV64
201bdd1243dSDimitry Andric // saving PC, 12 int regs, sp, 12 fp regs
202bdd1243dSDimitry Andric #    ifndef __riscv_float_abi_soft
203bdd1243dSDimitry Andric constexpr size_t kHwRegisterBufSize = 1 + 12 + 1 + 12;
204bdd1243dSDimitry Andric #    else
205bdd1243dSDimitry Andric constexpr size_t kHwRegisterBufSize = 1 + 12 + 1;
206bdd1243dSDimitry Andric #    endif
207349cc55cSDimitry Andric #  endif
208349cc55cSDimitry Andric typedef unsigned long long __hw_register_buf[kHwRegisterBufSize];
209480093f4SDimitry Andric struct __hw_jmp_buf_struct {
210480093f4SDimitry Andric   // NOTE: The machine-dependent definition of `__sigsetjmp'
211480093f4SDimitry Andric   // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that
212480093f4SDimitry Andric   // `__mask_was_saved' follows it.  Do not move these members or add others
213480093f4SDimitry Andric   // before it.
214349cc55cSDimitry Andric   //
215349cc55cSDimitry Andric   // We add a __magic field to our struct to catch cases where libc's setjmp
216349cc55cSDimitry Andric   // populated the jmp_buf instead of our interceptor.
217480093f4SDimitry Andric   __hw_register_buf __jmpbuf; // Calling environment.
218349cc55cSDimitry Andric   unsigned __mask_was_saved : 1;  // Saved the signal mask?
219349cc55cSDimitry Andric   unsigned __magic : 31;      // Used to distinguish __hw_jmp_buf from jmp_buf.
220480093f4SDimitry Andric   __hw_sigset_t __saved_mask; // Saved signal mask.
221480093f4SDimitry Andric };
222480093f4SDimitry Andric typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1];
223480093f4SDimitry Andric typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1];
224349cc55cSDimitry Andric constexpr unsigned kHwJmpBufMagic = 0x248ACE77;
225349cc55cSDimitry Andric #endif  // HWASAN_WITH_INTERCEPTORS
226480093f4SDimitry Andric 
227fe6060f1SDimitry Andric #define ENSURE_HWASAN_INITED()      \
228fe6060f1SDimitry Andric   do {                              \
229fe6060f1SDimitry Andric     CHECK(!hwasan_init_is_running); \
230fe6060f1SDimitry Andric     if (!hwasan_inited) {           \
231fe6060f1SDimitry Andric       __hwasan_init();              \
232fe6060f1SDimitry Andric     }                               \
233fe6060f1SDimitry Andric   } while (0)
234fe6060f1SDimitry Andric 
2350b57cec5SDimitry Andric #endif  // HWASAN_H
236