Skip to content
This repository was archived by the owner on May 21, 2019. It is now read-only.

Commit f7d5f65

Browse files
committed
[hwasan] Implement -fsanitize-recover=hwaddress.
Summary: Very similar to AddressSanitizer, with the exception of the error type encoding. Reviewers: kcc, alekseyshl Subscribers: cfe-commits, kubamracek, llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D41417 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@321203 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 1d871d6 commit f7d5f65

File tree

4 files changed

+154
-36
lines changed

4 files changed

+154
-36
lines changed

lib/hwasan/hwasan.cc

+95-23
Original file line numberDiff line numberDiff line change
@@ -252,40 +252,112 @@ static void SigIll() {
252252
// __builtin_unreachable();
253253
}
254254

255-
template<bool IsStore, unsigned LogSize>
256-
__attribute__((always_inline, nodebug))
257-
static void CheckAddress(uptr p) {
255+
enum class ErrorAction { Abort, Recover };
256+
enum class AccessType { Load, Store };
257+
258+
template <ErrorAction EA, AccessType AT, unsigned LogSize>
259+
__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
258260
tag_t ptr_tag = GetTagFromPointer(p);
259261
uptr ptr_raw = p & ~kAddressTagMask;
260262
tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);
261-
if (UNLIKELY(ptr_tag != mem_tag)) SigIll<0x100 + 0x10 * IsStore + LogSize>();
263+
if (UNLIKELY(ptr_tag != mem_tag)) {
264+
SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) +
265+
0x10 * (AT == AccessType::Store) + LogSize>();
266+
if (EA == ErrorAction::Abort) __builtin_unreachable();
267+
}
262268
}
263269

264-
template<bool IsStore>
265-
__attribute__((always_inline, nodebug))
266-
static void CheckAddressSized(uptr p, uptr sz) {
270+
template <ErrorAction EA, AccessType AT>
271+
__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
272+
uptr sz) {
267273
CHECK_NE(0, sz);
268274
tag_t ptr_tag = GetTagFromPointer(p);
269275
uptr ptr_raw = p & ~kAddressTagMask;
270276
tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw);
271277
tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1);
272278
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
273-
if (UNLIKELY(ptr_tag != *t)) SigIll<0x100 + 0x10 * IsStore + 0xf>();
274-
}
275-
276-
void __hwasan_load(uptr p, uptr sz) { CheckAddressSized<false>(p, sz); }
277-
void __hwasan_load1(uptr p) { CheckAddress<false, 0>(p); }
278-
void __hwasan_load2(uptr p) { CheckAddress<false, 1>(p); }
279-
void __hwasan_load4(uptr p) { CheckAddress<false, 2>(p); }
280-
void __hwasan_load8(uptr p) { CheckAddress<false, 3>(p); }
281-
void __hwasan_load16(uptr p) { CheckAddress<false, 4>(p); }
282-
283-
void __hwasan_store(uptr p, uptr sz) { CheckAddressSized<true>(p, sz); }
284-
void __hwasan_store1(uptr p) { CheckAddress<true, 0>(p); }
285-
void __hwasan_store2(uptr p) { CheckAddress<true, 1>(p); }
286-
void __hwasan_store4(uptr p) { CheckAddress<true, 2>(p); }
287-
void __hwasan_store8(uptr p) { CheckAddress<true, 3>(p); }
288-
void __hwasan_store16(uptr p) { CheckAddress<true, 4>(p); }
279+
if (UNLIKELY(ptr_tag != *t)) {
280+
SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) +
281+
0x10 * (AT == AccessType::Store) + 0xf>();
282+
if (EA == ErrorAction::Abort) __builtin_unreachable();
283+
}
284+
}
285+
286+
void __hwasan_load(uptr p, uptr sz) {
287+
CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
288+
}
289+
void __hwasan_load1(uptr p) {
290+
CheckAddress<ErrorAction::Abort, AccessType::Load, 0>(p);
291+
}
292+
void __hwasan_load2(uptr p) {
293+
CheckAddress<ErrorAction::Abort, AccessType::Load, 1>(p);
294+
}
295+
void __hwasan_load4(uptr p) {
296+
CheckAddress<ErrorAction::Abort, AccessType::Load, 2>(p);
297+
}
298+
void __hwasan_load8(uptr p) {
299+
CheckAddress<ErrorAction::Abort, AccessType::Load, 3>(p);
300+
}
301+
void __hwasan_load16(uptr p) {
302+
CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p);
303+
}
304+
305+
void __hwasan_load_noabort(uptr p, uptr sz) {
306+
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz);
307+
}
308+
void __hwasan_load1_noabort(uptr p) {
309+
CheckAddress<ErrorAction::Recover, AccessType::Load, 0>(p);
310+
}
311+
void __hwasan_load2_noabort(uptr p) {
312+
CheckAddress<ErrorAction::Recover, AccessType::Load, 1>(p);
313+
}
314+
void __hwasan_load4_noabort(uptr p) {
315+
CheckAddress<ErrorAction::Recover, AccessType::Load, 2>(p);
316+
}
317+
void __hwasan_load8_noabort(uptr p) {
318+
CheckAddress<ErrorAction::Recover, AccessType::Load, 3>(p);
319+
}
320+
void __hwasan_load16_noabort(uptr p) {
321+
CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p);
322+
}
323+
324+
void __hwasan_store(uptr p, uptr sz) {
325+
CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz);
326+
}
327+
void __hwasan_store1(uptr p) {
328+
CheckAddress<ErrorAction::Abort, AccessType::Store, 0>(p);
329+
}
330+
void __hwasan_store2(uptr p) {
331+
CheckAddress<ErrorAction::Abort, AccessType::Store, 1>(p);
332+
}
333+
void __hwasan_store4(uptr p) {
334+
CheckAddress<ErrorAction::Abort, AccessType::Store, 2>(p);
335+
}
336+
void __hwasan_store8(uptr p) {
337+
CheckAddress<ErrorAction::Abort, AccessType::Store, 3>(p);
338+
}
339+
void __hwasan_store16(uptr p) {
340+
CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p);
341+
}
342+
343+
void __hwasan_store_noabort(uptr p, uptr sz) {
344+
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz);
345+
}
346+
void __hwasan_store1_noabort(uptr p) {
347+
CheckAddress<ErrorAction::Recover, AccessType::Store, 0>(p);
348+
}
349+
void __hwasan_store2_noabort(uptr p) {
350+
CheckAddress<ErrorAction::Recover, AccessType::Store, 1>(p);
351+
}
352+
void __hwasan_store4_noabort(uptr p) {
353+
CheckAddress<ErrorAction::Recover, AccessType::Store, 2>(p);
354+
}
355+
void __hwasan_store8_noabort(uptr p) {
356+
CheckAddress<ErrorAction::Recover, AccessType::Store, 3>(p);
357+
}
358+
void __hwasan_store16_noabort(uptr p) {
359+
CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p);
360+
}
289361

290362
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
291363
extern "C" {

lib/hwasan/hwasan_interface_internal.h

+26
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ void __hwasan_load8(uptr);
4444
SANITIZER_INTERFACE_ATTRIBUTE
4545
void __hwasan_load16(uptr);
4646

47+
SANITIZER_INTERFACE_ATTRIBUTE
48+
void __hwasan_load_noabort(uptr, uptr);
49+
SANITIZER_INTERFACE_ATTRIBUTE
50+
void __hwasan_load1_noabort(uptr);
51+
SANITIZER_INTERFACE_ATTRIBUTE
52+
void __hwasan_load2_noabort(uptr);
53+
SANITIZER_INTERFACE_ATTRIBUTE
54+
void __hwasan_load4_noabort(uptr);
55+
SANITIZER_INTERFACE_ATTRIBUTE
56+
void __hwasan_load8_noabort(uptr);
57+
SANITIZER_INTERFACE_ATTRIBUTE
58+
void __hwasan_load16_noabort(uptr);
59+
4760
SANITIZER_INTERFACE_ATTRIBUTE
4861
void __hwasan_store(uptr, uptr);
4962
SANITIZER_INTERFACE_ATTRIBUTE
@@ -57,6 +70,19 @@ void __hwasan_store8(uptr);
5770
SANITIZER_INTERFACE_ATTRIBUTE
5871
void __hwasan_store16(uptr);
5972

73+
SANITIZER_INTERFACE_ATTRIBUTE
74+
void __hwasan_store_noabort(uptr, uptr);
75+
SANITIZER_INTERFACE_ATTRIBUTE
76+
void __hwasan_store1_noabort(uptr);
77+
SANITIZER_INTERFACE_ATTRIBUTE
78+
void __hwasan_store2_noabort(uptr);
79+
SANITIZER_INTERFACE_ATTRIBUTE
80+
void __hwasan_store4_noabort(uptr);
81+
SANITIZER_INTERFACE_ATTRIBUTE
82+
void __hwasan_store8_noabort(uptr);
83+
SANITIZER_INTERFACE_ATTRIBUTE
84+
void __hwasan_store16_noabort(uptr);
85+
6086
// Returns the offset of the first tag mismatch or -1 if the whole range is
6187
// good.
6288
SANITIZER_INTERFACE_ATTRIBUTE

lib/hwasan/hwasan_linux.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ struct AccessInfo {
174174
uptr size;
175175
bool is_store;
176176
bool is_load;
177+
bool recover;
177178
};
178179

179180
#if defined(__aarch64__)
180181
static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
181182
// Access type is encoded in HLT immediate as 0x1XY,
182-
// where X is 1 for store, 0 for load.
183+
// where X&1 is 1 for store, 0 for load,
184+
// and X&2 is 1 if the error is recoverable.
183185
// Valid values of Y are 0 to 4, which are interpreted as log2(access_size),
184186
// and 0xF, which means that access size is stored in X1 register.
185187
// Access address is always in X0 register.
@@ -189,6 +191,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
189191
if ((code & 0xff00) != 0x100)
190192
return AccessInfo{0, 0, false, false}; // Not ours.
191193
bool is_store = code & 0x10;
194+
bool recover = code & 0x20;
192195
unsigned size_log = code & 0xf;
193196
if (size_log > 4 && size_log != 0xf)
194197
return AccessInfo{0, 0, false, false}; // Not ours.
@@ -200,6 +203,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) {
200203
ai.size = uc->uc_mcontext.regs[1];
201204
else
202205
ai.size = 1U << size_log;
206+
ai.recover = recover;
203207
return ai;
204208
}
205209
#else
@@ -223,7 +227,7 @@ static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) {
223227
ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);
224228

225229
++hwasan_report_count;
226-
if (flags()->halt_on_error)
230+
if (flags()->halt_on_error || !ai.recover)
227231
Die();
228232

229233
uc->uc_mcontext.pc += 4;
+27-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,19 @@
1-
// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s
1+
// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON
2+
// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
3+
// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
4+
5+
// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
6+
// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
7+
// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER
8+
9+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
10+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
11+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
12+
13+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
14+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON
15+
// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t -fsanitize-recover=hwaddress && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON,RECOVER
16+
217
// REQUIRES: stable-runtime
318

419
#include <stdlib.h>
@@ -10,17 +25,18 @@ int main() {
1025
free(x);
1126
__hwasan_disable_allocator_tagging();
1227
return x[2] + ((char *)x)[6] + ((char *)x)[9];
13-
// CHECK: READ of size 4 at
14-
// CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
15-
// CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
28+
// COMMON: READ of size 4 at
29+
// When instrumenting with callbacks, main is actually #1, and #0 is __hwasan_load4.
30+
// COMMON: #{{.*}} in main {{.*}}halt-on-error.cc:27
31+
// COMMON: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
1632

17-
// CHECK: READ of size 1 at
18-
// CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
19-
// CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
33+
// RECOVER: READ of size 1 at
34+
// RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27
35+
// RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
2036

21-
// CHECK: READ of size 1 at
22-
// CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12
23-
// CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main
37+
// RECOVER: READ of size 1 at
38+
// RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27
39+
// RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in
2440

25-
// CHECK-NOT: tag-mismatch
41+
// COMMON-NOT: tag-mismatch
2642
}

0 commit comments

Comments
 (0)