1 //===-- hwasan_checks.h -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of HWAddressSanitizer.
11 //===----------------------------------------------------------------------===//
13 #ifndef HWASAN_CHECKS_H
14 #define HWASAN_CHECKS_H
16 #include "hwasan_allocator.h"
17 #include "hwasan_mapping.h"
18 #include "hwasan_registers.h"
19 #include "sanitizer_common/sanitizer_common.h"
23 enum class ErrorAction
{ Abort
, Recover
};
24 enum class AccessType
{ Load
, Store
};
26 // Used when the access size is known.
27 constexpr unsigned SigTrapEncoding(ErrorAction EA
, AccessType AT
,
29 return 0x20 * (EA
== ErrorAction::Recover
) +
30 0x10 * (AT
== AccessType::Store
) + LogSize
;
33 // Used when the access size varies at runtime.
34 constexpr unsigned SigTrapEncoding(ErrorAction EA
, AccessType AT
) {
35 return SigTrapEncoding(EA
, AT
, 0xf);
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
= {
49 .is_store
= AT
== AccessType::Store
,
50 .is_load
= AT
== AccessType::Load
,
51 .recover
= EA
== ErrorAction::Recover
,
53 HandleTagMismatch(access_info
, (uptr
)__builtin_return_address(0),
54 (uptr
)__builtin_frame_address(0), /*uc=*/nullptr, regs
.x
);
55 #elif defined(__aarch64__)
57 // 0x900 is added to do not interfere with the kernel use of lower values of
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).
69 "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA
, AT
, LogSize
)),
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
;
78 "addiw x0, x0, %1\n" ::"r"(x10
),
79 "I"(0x40 + SigTrapEncoding(EA
, AT
, LogSize
)));
81 // FIXME: not always sigill.
84 // __builtin_unreachable();
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
= {
98 .is_store
= AT
== AccessType::Store
,
99 .is_load
= AT
== AccessType::Load
,
100 .recover
= EA
== ErrorAction::Recover
,
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.
112 "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA
, AT
)),
114 #elif SANITIZER_RISCV64
115 // Put access size into x11
116 register uptr x10
asm("x10") = p
;
117 register uptr x11
asm("x11") = size
;
120 "addiw x0, x0, %2\n" ::"r"(x10
),
121 "r"(x11
), "I"(0x40 + SigTrapEncoding(EA
, AT
)));
125 // __builtin_unreachable();
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
)
136 if (*(u8
*)(ptr
| (kShadowAlignment
- 1)) != ptr_tag
)
141 __attribute__((always_inline
, nodebug
)) static inline bool
142 PossiblyShortTagMatches(tag_t mem_tag
, uptr ptr
, uptr sz
) {
143 DCHECK(IsAligned(ptr
, kShadowAlignment
));
144 tag_t ptr_tag
= GetTagFromPointer(ptr
);
145 if (ptr_tag
== mem_tag
)
147 if (mem_tag
>= kShadowAlignment
)
149 if ((ptr
& (kShadowAlignment
- 1)) + sz
> mem_tag
)
151 return *(u8
*)(ptr
| (kShadowAlignment
- 1)) == ptr_tag
;
154 template <ErrorAction EA
, AccessType AT
, unsigned LogSize
>
155 __attribute__((always_inline
, nodebug
)) static void CheckAddress(uptr p
) {
156 if (!InTaggableRegion(p
))
158 uptr ptr_raw
= p
& ~kAddressTagMask
;
159 tag_t mem_tag
= *(tag_t
*)MemToShadow(ptr_raw
);
160 if (UNLIKELY(!PossiblyShortTagMatches(mem_tag
, p
, 1 << LogSize
))) {
161 SigTrap
<EA
, AT
, LogSize
>(p
);
162 if (EA
== ErrorAction::Abort
)
163 __builtin_unreachable();
167 template <ErrorAction EA
, AccessType AT
>
168 __attribute__((always_inline
, nodebug
)) static void CheckAddressSized(uptr p
,
170 if (sz
== 0 || !InTaggableRegion(p
))
172 tag_t ptr_tag
= GetTagFromPointer(p
);
173 uptr ptr_raw
= p
& ~kAddressTagMask
;
174 tag_t
*shadow_first
= (tag_t
*)MemToShadow(ptr_raw
);
175 tag_t
*shadow_last
= (tag_t
*)MemToShadow(ptr_raw
+ sz
);
176 for (tag_t
*t
= shadow_first
; t
< shadow_last
; ++t
)
177 if (UNLIKELY(ptr_tag
!= *t
)) {
178 SigTrap
<EA
, AT
>(p
, sz
);
179 if (EA
== ErrorAction::Abort
)
180 __builtin_unreachable();
183 uptr tail_sz
= end
& (kShadowAlignment
- 1);
184 if (UNLIKELY(tail_sz
!= 0 &&
185 !PossiblyShortTagMatches(
186 *shadow_last
, end
& ~(kShadowAlignment
- 1), tail_sz
))) {
187 SigTrap
<EA
, AT
>(p
, sz
);
188 if (EA
== ErrorAction::Abort
)
189 __builtin_unreachable();
193 } // end namespace __hwasan
195 #endif // HWASAN_CHECKS_H