diff options
author | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2017-12-20 19:05:44 +0000 |
---|---|---|
committer | Evgeniy Stepanov <eugeni.stepanov@gmail.com> | 2017-12-20 19:05:44 +0000 |
commit | 3fd1b1a764c856c11748619ca5fecf5b22ef0880 (patch) | |
tree | 15b14e594d84d7351729c1555bba87a0ea30ff1e /compiler-rt | |
parent | f7f59b529293136d0f711b86dbfccb525d0677d4 (diff) | |
download | llvm-3fd1b1a764c856c11748619ca5fecf5b22ef0880.zip llvm-3fd1b1a764c856c11748619ca5fecf5b22ef0880.tar.gz llvm-3fd1b1a764c856c11748619ca5fecf5b22ef0880.tar.bz2 |
[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
llvm-svn: 321203
Diffstat (limited to 'compiler-rt')
-rw-r--r-- | compiler-rt/lib/hwasan/hwasan.cc | 118 | ||||
-rw-r--r-- | compiler-rt/lib/hwasan/hwasan_interface_internal.h | 26 | ||||
-rw-r--r-- | compiler-rt/lib/hwasan/hwasan_linux.cc | 8 | ||||
-rw-r--r-- | compiler-rt/test/hwasan/TestCases/halt-on-error.cc | 38 |
4 files changed, 154 insertions, 36 deletions
diff --git a/compiler-rt/lib/hwasan/hwasan.cc b/compiler-rt/lib/hwasan/hwasan.cc index fcc40eb..8b1e5a7 100644 --- a/compiler-rt/lib/hwasan/hwasan.cc +++ b/compiler-rt/lib/hwasan/hwasan.cc @@ -252,40 +252,112 @@ static void SigIll() { // __builtin_unreachable(); } -template<bool IsStore, unsigned LogSize> -__attribute__((always_inline, nodebug)) -static void CheckAddress(uptr p) { +enum class ErrorAction { Abort, Recover }; +enum class AccessType { Load, Store }; + +template <ErrorAction EA, AccessType AT, unsigned LogSize> +__attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) { tag_t ptr_tag = GetTagFromPointer(p); uptr ptr_raw = p & ~kAddressTagMask; tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw); - if (UNLIKELY(ptr_tag != mem_tag)) SigIll<0x100 + 0x10 * IsStore + LogSize>(); + if (UNLIKELY(ptr_tag != mem_tag)) { + SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + + 0x10 * (AT == AccessType::Store) + LogSize>(); + if (EA == ErrorAction::Abort) __builtin_unreachable(); + } } -template<bool IsStore> -__attribute__((always_inline, nodebug)) -static void CheckAddressSized(uptr p, uptr sz) { +template <ErrorAction EA, AccessType AT> +__attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p, + uptr sz) { CHECK_NE(0, sz); tag_t ptr_tag = GetTagFromPointer(p); uptr ptr_raw = p & ~kAddressTagMask; tag_t *shadow_first = (tag_t *)MEM_TO_SHADOW(ptr_raw); tag_t *shadow_last = (tag_t *)MEM_TO_SHADOW(ptr_raw + sz - 1); for (tag_t *t = shadow_first; t <= shadow_last; ++t) - if (UNLIKELY(ptr_tag != *t)) SigIll<0x100 + 0x10 * IsStore + 0xf>(); -} - -void __hwasan_load(uptr p, uptr sz) { CheckAddressSized<false>(p, sz); } -void __hwasan_load1(uptr p) { CheckAddress<false, 0>(p); } -void __hwasan_load2(uptr p) { CheckAddress<false, 1>(p); } -void __hwasan_load4(uptr p) { CheckAddress<false, 2>(p); } -void __hwasan_load8(uptr p) { CheckAddress<false, 3>(p); } -void __hwasan_load16(uptr p) { CheckAddress<false, 4>(p); } - -void __hwasan_store(uptr p, uptr sz) { CheckAddressSized<true>(p, sz); } -void __hwasan_store1(uptr p) { CheckAddress<true, 0>(p); } -void __hwasan_store2(uptr p) { CheckAddress<true, 1>(p); } -void __hwasan_store4(uptr p) { CheckAddress<true, 2>(p); } -void __hwasan_store8(uptr p) { CheckAddress<true, 3>(p); } -void __hwasan_store16(uptr p) { CheckAddress<true, 4>(p); } + if (UNLIKELY(ptr_tag != *t)) { + SigIll<0x100 + 0x20 * (EA == ErrorAction::Recover) + + 0x10 * (AT == AccessType::Store) + 0xf>(); + if (EA == ErrorAction::Abort) __builtin_unreachable(); + } +} + +void __hwasan_load(uptr p, uptr sz) { + CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz); +} +void __hwasan_load1(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Load, 0>(p); +} +void __hwasan_load2(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Load, 1>(p); +} +void __hwasan_load4(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Load, 2>(p); +} +void __hwasan_load8(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Load, 3>(p); +} +void __hwasan_load16(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Load, 4>(p); +} + +void __hwasan_load_noabort(uptr p, uptr sz) { + CheckAddressSized<ErrorAction::Recover, AccessType::Load>(p, sz); +} +void __hwasan_load1_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Load, 0>(p); +} +void __hwasan_load2_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Load, 1>(p); +} +void __hwasan_load4_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Load, 2>(p); +} +void __hwasan_load8_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Load, 3>(p); +} +void __hwasan_load16_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Load, 4>(p); +} + +void __hwasan_store(uptr p, uptr sz) { + CheckAddressSized<ErrorAction::Abort, AccessType::Store>(p, sz); +} +void __hwasan_store1(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Store, 0>(p); +} +void __hwasan_store2(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Store, 1>(p); +} +void __hwasan_store4(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Store, 2>(p); +} +void __hwasan_store8(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Store, 3>(p); +} +void __hwasan_store16(uptr p) { + CheckAddress<ErrorAction::Abort, AccessType::Store, 4>(p); +} + +void __hwasan_store_noabort(uptr p, uptr sz) { + CheckAddressSized<ErrorAction::Recover, AccessType::Store>(p, sz); +} +void __hwasan_store1_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Store, 0>(p); +} +void __hwasan_store2_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Store, 1>(p); +} +void __hwasan_store4_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Store, 2>(p); +} +void __hwasan_store8_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Store, 3>(p); +} +void __hwasan_store16_noabort(uptr p) { + CheckAddress<ErrorAction::Recover, AccessType::Store, 4>(p); +} #if !SANITIZER_SUPPORTS_WEAK_HOOKS extern "C" { diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h index 08b7753..7e95271 100644 --- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -45,6 +45,19 @@ SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_load16(uptr); SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load_noabort(uptr, uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load1_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load2_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load4_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load8_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_load16_noabort(uptr); + +SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_store(uptr, uptr); SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_store1(uptr); @@ -57,6 +70,19 @@ void __hwasan_store8(uptr); SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_store16(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store_noabort(uptr, uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store1_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store2_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store4_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store8_noabort(uptr); +SANITIZER_INTERFACE_ATTRIBUTE +void __hwasan_store16_noabort(uptr); + // Returns the offset of the first tag mismatch or -1 if the whole range is // good. SANITIZER_INTERFACE_ATTRIBUTE diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cc b/compiler-rt/lib/hwasan/hwasan_linux.cc index 2640469..48dea8e 100644 --- a/compiler-rt/lib/hwasan/hwasan_linux.cc +++ b/compiler-rt/lib/hwasan/hwasan_linux.cc @@ -174,12 +174,14 @@ struct AccessInfo { uptr size; bool is_store; bool is_load; + bool recover; }; #if defined(__aarch64__) static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { // Access type is encoded in HLT immediate as 0x1XY, - // where X is 1 for store, 0 for load. + // where X&1 is 1 for store, 0 for load, + // and X&2 is 1 if the error is recoverable. // Valid values of Y are 0 to 4, which are interpreted as log2(access_size), // and 0xF, which means that access size is stored in X1 register. // Access address is always in X0 register. @@ -189,6 +191,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { if ((code & 0xff00) != 0x100) return AccessInfo{0, 0, false, false}; // Not ours. bool is_store = code & 0x10; + bool recover = code & 0x20; unsigned size_log = code & 0xf; if (size_log > 4 && size_log != 0xf) return AccessInfo{0, 0, false, false}; // Not ours. @@ -200,6 +203,7 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { ai.size = uc->uc_mcontext.regs[1]; else ai.size = 1U << size_log; + ai.recover = recover; return ai; } #else @@ -223,7 +227,7 @@ static bool HwasanOnSIGILL(int signo, siginfo_t *info, ucontext_t *uc) { ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store); ++hwasan_report_count; - if (flags()->halt_on_error) + if (flags()->halt_on_error || !ai.recover) Die(); uc->uc_mcontext.pc += 4; diff --git a/compiler-rt/test/hwasan/TestCases/halt-on-error.cc b/compiler-rt/test/hwasan/TestCases/halt-on-error.cc index 7c3cc5c..fdf6d27 100644 --- a/compiler-rt/test/hwasan/TestCases/halt-on-error.cc +++ b/compiler-rt/test/hwasan/TestCases/halt-on-error.cc @@ -1,4 +1,19 @@ -// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_hwasan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefixes=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=1 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// RUN: %clangxx_hwasan -O0 %s -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=COMMON + +// RUN: %clangxx_hwasan -O0 %s -o %t -fsanitize-recover=hwaddress && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// 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 +// 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 + +// RUN: %clangxx_hwasan -mllvm -hwasan-instrument-with-calls=1 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=COMMON +// 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 +// 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 + +// 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 +// 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 +// 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 + // REQUIRES: stable-runtime #include <stdlib.h> @@ -10,17 +25,18 @@ int main() { free(x); __hwasan_disable_allocator_tagging(); return x[2] + ((char *)x)[6] + ((char *)x)[9]; - // CHECK: READ of size 4 at - // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 - // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main + // COMMON: READ of size 4 at + // When instrumenting with callbacks, main is actually #1, and #0 is __hwasan_load4. + // COMMON: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // COMMON: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in - // CHECK: READ of size 1 at - // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 - // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main + // RECOVER: READ of size 1 at + // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in - // CHECK: READ of size 1 at - // CHECK: #0 {{.*}} in main {{.*}}halt-on-error.cc:12 - // CHECK: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in main + // RECOVER: READ of size 1 at + // RECOVER: #{{.*}} in main {{.*}}halt-on-error.cc:27 + // RECOVER: SUMMARY: HWAddressSanitizer: tag-mismatch {{.*}} in - // CHECK-NOT: tag-mismatch + // COMMON-NOT: tag-mismatch } |