summaryrefslogtreecommitdiff
path: root/libsanitizer/hwasan/hwasan.h
blob: 371c43f3cbde7fe3fa2690683214f00484242e57 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//===-- hwasan.h ------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is a part of HWAddressSanitizer.
//
// Private Hwasan header.
//===----------------------------------------------------------------------===//

#ifndef HWASAN_H
#define HWASAN_H

#include "hwasan_flags.h"
#include "hwasan_interface_internal.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "ubsan/ubsan_platform.h"

#ifndef HWASAN_CONTAINS_UBSAN
# define HWASAN_CONTAINS_UBSAN CAN_SANITIZE_UB
#endif

#ifndef HWASAN_WITH_INTERCEPTORS
#define HWASAN_WITH_INTERCEPTORS 0
#endif

#ifndef HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE
#define HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE HWASAN_WITH_INTERCEPTORS
#endif

typedef u8 tag_t;

#if defined(HWASAN_ALIASING_MODE)
#  if !defined(__x86_64__)
#    error Aliasing mode is only supported on x86_64
#  endif
// Tags are done in middle bits using userspace aliasing.
constexpr unsigned kAddressTagShift = 39;
constexpr unsigned kTagBits = 3;

// The alias region is placed next to the shadow so the upper bits of all
// taggable addresses matches the upper bits of the shadow base.  This shift
// value determines which upper bits must match.  It has a floor of 44 since the
// shadow is always 8TB.
// TODO(morehouse): In alias mode we can shrink the shadow and use a
// simpler/faster shadow calculation.
constexpr unsigned kTaggableRegionCheckShift =
    __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
#elif defined(__x86_64__)
// Tags are done in upper bits using Intel LAM.
constexpr unsigned kAddressTagShift = 57;
constexpr unsigned kTagBits = 6;
#else
// TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
// translation and can be used to store a tag.
constexpr unsigned kAddressTagShift = 56;
constexpr unsigned kTagBits = 8;
#endif  // defined(HWASAN_ALIASING_MODE)

// Mask for extracting tag bits from the lower 8 bits.
constexpr uptr kTagMask = (1UL << kTagBits) - 1;

// Mask for extracting tag bits from full pointers.
constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;

// Minimal alignment of the shadow base address. Determines the space available
// for threads and stack histories. This is an ABI constant.
const unsigned kShadowBaseAlignment = 32;

const unsigned kRecordAddrBaseTagShift = 3;
const unsigned kRecordFPShift = 48;
const unsigned kRecordFPLShift = 4;
const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);

static inline tag_t GetTagFromPointer(uptr p) {
  return (p >> kAddressTagShift) & kTagMask;
}

static inline uptr UntagAddr(uptr tagged_addr) {
  return tagged_addr & ~kAddressTagMask;
}

static inline void *UntagPtr(const void *tagged_ptr) {
  return reinterpret_cast<void *>(
      UntagAddr(reinterpret_cast<uptr>(tagged_ptr)));
}

static inline uptr AddTagToPointer(uptr p, tag_t tag) {
  return (p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift);
}

namespace __hwasan {

extern int hwasan_inited;
extern bool hwasan_init_is_running;
extern int hwasan_report_count;

bool InitShadow();
void InitializeOsSupport();
void InitThreads();
void InitializeInterceptors();

void HwasanAllocatorInit();
void HwasanAllocatorLock();
void HwasanAllocatorUnlock();

void *hwasan_malloc(uptr size, StackTrace *stack);
void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack);
void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack);
void *hwasan_reallocarray(void *ptr, uptr nmemb, uptr size, StackTrace *stack);
void *hwasan_valloc(uptr size, StackTrace *stack);
void *hwasan_pvalloc(uptr size, StackTrace *stack);
void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack);
void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack);
int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
                        StackTrace *stack);
void hwasan_free(void *ptr, StackTrace *stack);

void InstallAtExitHandler();

#define GET_MALLOC_STACK_TRACE                                            \
  BufferedStackTrace stack;                                               \
  if (hwasan_inited)                                                      \
    stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \
                 nullptr, common_flags()->fast_unwind_on_malloc,          \
                 common_flags()->malloc_context_size)

#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \
  BufferedStackTrace stack;                              \
  if (hwasan_inited)                                     \
    stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)

void HwasanTSDInit();
void HwasanTSDThreadInit();
void HwasanAtExit();

void HwasanOnDeadlySignal(int signo, void *info, void *context);

void HwasanInstallAtForkHandler();

void UpdateMemoryUsage();

void AppendToErrorMessageBuffer(const char *buffer);

void AndroidTestTlsSlot();

// This is a compiler-generated struct that can be shared between hwasan
// implementations.
struct AccessInfo {
  uptr addr;
  uptr size;
  bool is_store;
  bool is_load;
  bool recover;
};

// Given access info and frame information, unwind the stack and report the tag
// mismatch.
void HandleTagMismatch(AccessInfo ai, uptr pc, uptr frame, void *uc,
                       uptr *registers_frame = nullptr);

// This dispatches to HandleTagMismatch but sets up the AccessInfo, program
// counter, and frame pointer.
void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame,
                       size_t outsize);

}  // namespace __hwasan

#define HWASAN_MALLOC_HOOK(ptr, size)       \
  do {                                    \
    if (&__sanitizer_malloc_hook) {       \
      __sanitizer_malloc_hook(ptr, size); \
    }                                     \
    RunMallocHooks(ptr, size);            \
  } while (false)
#define HWASAN_FREE_HOOK(ptr)       \
  do {                            \
    if (&__sanitizer_free_hook) { \
      __sanitizer_free_hook(ptr); \
    }                             \
    RunFreeHooks(ptr);            \
  } while (false)

#if HWASAN_WITH_INTERCEPTORS
// For both bionic and glibc __sigset_t is an unsigned long.
typedef unsigned long __hw_sigset_t;
// Setjmp and longjmp implementations are platform specific, and hence the
// interception code is platform specific too.
#  if defined(__aarch64__)
constexpr size_t kHwRegisterBufSize = 22;
#  elif defined(__x86_64__)
constexpr size_t kHwRegisterBufSize = 8;
#  endif
typedef unsigned long long __hw_register_buf[kHwRegisterBufSize];
struct __hw_jmp_buf_struct {
  // NOTE: The machine-dependent definition of `__sigsetjmp'
  // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that
  // `__mask_was_saved' follows it.  Do not move these members or add others
  // before it.
  //
  // We add a __magic field to our struct to catch cases where libc's setjmp
  // populated the jmp_buf instead of our interceptor.
  __hw_register_buf __jmpbuf; // Calling environment.
  unsigned __mask_was_saved : 1;  // Saved the signal mask?
  unsigned __magic : 31;      // Used to distinguish __hw_jmp_buf from jmp_buf.
  __hw_sigset_t __saved_mask; // Saved signal mask.
};
typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1];
typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1];
constexpr unsigned kHwJmpBufMagic = 0x248ACE77;
#endif  // HWASAN_WITH_INTERCEPTORS

#define ENSURE_HWASAN_INITED()      \
  do {                              \
    CHECK(!hwasan_init_is_running); \
    if (!hwasan_inited) {           \
      __hwasan_init();              \
    }                               \
  } while (0)

#endif  // HWASAN_H