Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/hwasan/hwasan_checks.h
35236 views
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 "hwasan_registers.h"
19
#include "sanitizer_common/sanitizer_common.h"
20
21
namespace __hwasan {
22
23
enum class ErrorAction { Abort, Recover };
24
enum class AccessType { Load, Store };
25
26
// Used when the access size is known.
27
constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT,
28
unsigned LogSize) {
29
return 0x20 * (EA == ErrorAction::Recover) +
30
0x10 * (AT == AccessType::Store) + LogSize;
31
}
32
33
// Used when the access size varies at runtime.
34
constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT) {
35
return SigTrapEncoding(EA, AT, 0xf);
36
}
37
38
template <ErrorAction EA, AccessType AT, size_t LogSize>
39
__attribute__((always_inline)) static void SigTrap(uptr p) {
40
// Other platforms like linux can use signals for intercepting an exception
41
// and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
42
// use signals so we can call it here directly instead.
43
#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
44
auto regs = GetRegisters();
45
size_t size = 2 << LogSize;
46
AccessInfo access_info = {
47
.addr = p,
48
.size = size,
49
.is_store = AT == AccessType::Store,
50
.is_load = AT == AccessType::Load,
51
.recover = EA == ErrorAction::Recover,
52
};
53
HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
54
(uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
55
#elif defined(__aarch64__)
56
(void)p;
57
// 0x900 is added to do not interfere with the kernel use of lower values of
58
// brk immediate.
59
register uptr x0 asm("x0") = p;
60
asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + SigTrapEncoding(EA, AT, LogSize)));
61
#elif defined(__x86_64__)
62
// INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
63
// total. The pointer is passed via rdi.
64
// 0x40 is added as a safeguard, to help distinguish our trap from others and
65
// to avoid 0 offsets in the command (otherwise it'll be reduced to a
66
// different nop command, the three bytes one).
67
asm volatile(
68
"int3\n"
69
"nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT, LogSize)),
70
"D"(p));
71
#elif SANITIZER_RISCV64
72
// Put pointer into x10
73
// addiw contains immediate of 0x40 + X, where 0x40 is magic number and X
74
// encodes access size
75
register uptr x10 asm("x10") = p;
76
asm volatile(
77
"ebreak\n"
78
"addiw x0, x0, %1\n" ::"r"(x10),
79
"I"(0x40 + SigTrapEncoding(EA, AT, LogSize)));
80
#else
81
// FIXME: not always sigill.
82
__builtin_trap();
83
#endif
84
// __builtin_unreachable();
85
}
86
87
// Version with access size which is not power of 2
88
template <ErrorAction EA, AccessType AT>
89
__attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
90
// Other platforms like linux can use signals for intercepting an exception
91
// and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
92
// use signals so we can call it here directly instead.
93
#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
94
auto regs = GetRegisters();
95
AccessInfo access_info = {
96
.addr = p,
97
.size = size,
98
.is_store = AT == AccessType::Store,
99
.is_load = AT == AccessType::Load,
100
.recover = EA == ErrorAction::Recover,
101
};
102
HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
103
(uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
104
#elif defined(__aarch64__)
105
register uptr x0 asm("x0") = p;
106
register uptr x1 asm("x1") = size;
107
asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + SigTrapEncoding(EA, AT)));
108
#elif defined(__x86_64__)
109
// Size is stored in rsi.
110
asm volatile(
111
"int3\n"
112
"nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT)),
113
"D"(p), "S"(size));
114
#elif SANITIZER_RISCV64
115
// Put access size into x11
116
register uptr x10 asm("x10") = p;
117
register uptr x11 asm("x11") = size;
118
asm volatile(
119
"ebreak\n"
120
"addiw x0, x0, %2\n" ::"r"(x10),
121
"r"(x11), "I"(0x40 + SigTrapEncoding(EA, AT)));
122
#else
123
__builtin_trap();
124
#endif
125
// __builtin_unreachable();
126
}
127
128
__attribute__((always_inline, nodebug)) static inline uptr ShortTagSize(
129
tag_t mem_tag, uptr ptr) {
130
DCHECK(IsAligned(ptr, kShadowAlignment));
131
tag_t ptr_tag = GetTagFromPointer(ptr);
132
if (ptr_tag == mem_tag)
133
return kShadowAlignment;
134
if (!mem_tag || mem_tag >= kShadowAlignment)
135
return 0;
136
if (*(u8 *)(ptr | (kShadowAlignment - 1)) != ptr_tag)
137
return 0;
138
return mem_tag;
139
}
140
141
__attribute__((always_inline, nodebug)) static inline bool
142
PossiblyShortTagMatches(tag_t mem_tag, uptr ptr, uptr sz) {
143
tag_t ptr_tag = GetTagFromPointer(ptr);
144
if (ptr_tag == mem_tag)
145
return true;
146
if (mem_tag >= kShadowAlignment)
147
return false;
148
if ((ptr & (kShadowAlignment - 1)) + sz > mem_tag)
149
return false;
150
return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag;
151
}
152
153
template <ErrorAction EA, AccessType AT, unsigned LogSize>
154
__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
155
if (!InTaggableRegion(p))
156
return;
157
uptr ptr_raw = p & ~kAddressTagMask;
158
tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
159
if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
160
SigTrap<EA, AT, LogSize>(p);
161
if (EA == ErrorAction::Abort)
162
__builtin_unreachable();
163
}
164
}
165
166
template <ErrorAction EA, AccessType AT>
167
__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
168
uptr sz) {
169
if (sz == 0 || !InTaggableRegion(p))
170
return;
171
tag_t ptr_tag = GetTagFromPointer(p);
172
uptr ptr_raw = p & ~kAddressTagMask;
173
tag_t *shadow_first = (tag_t *)MemToShadow(ptr_raw);
174
tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz);
175
for (tag_t *t = shadow_first; t < shadow_last; ++t)
176
if (UNLIKELY(ptr_tag != *t)) {
177
SigTrap<EA, AT>(p, sz);
178
if (EA == ErrorAction::Abort)
179
__builtin_unreachable();
180
}
181
uptr end = p + sz;
182
uptr tail_sz = end & (kShadowAlignment - 1);
183
if (UNLIKELY(tail_sz != 0 &&
184
!PossiblyShortTagMatches(
185
*shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) {
186
SigTrap<EA, AT>(p, sz);
187
if (EA == ErrorAction::Abort)
188
__builtin_unreachable();
189
}
190
}
191
192
} // end namespace __hwasan
193
194
#endif // HWASAN_CHECKS_H
195
196