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

Commit

Permalink
[hwasan] Implement -fsanitize-recover=hwaddress.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
eugenis committed Dec 20, 2017
1 parent 1d871d6 commit f7d5f65
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 36 deletions.
118 changes: 95 additions & 23 deletions lib/hwasan/hwasan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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" {
Expand Down
26 changes: 26 additions & 0 deletions lib/hwasan/hwasan_interface_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ void __hwasan_load8(uptr);
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
Expand All @@ -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
Expand Down
8 changes: 6 additions & 2 deletions lib/hwasan/hwasan_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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;
Expand Down
38 changes: 27 additions & 11 deletions test/hwasan/TestCases/halt-on-error.cc
Original file line number Diff line number Diff line change
@@ -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>
Expand All @@ -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
}

0 comments on commit f7d5f65

Please sign in to comment.