summaryrefslogtreecommitdiff
path: root/lib/hwasan/hwasan.cc
diff options
context:
space:
mode:
authorAlex Shlyapnikov <alekseys@google.com>2018-03-23 23:38:04 +0000
committerAlex Shlyapnikov <alekseys@google.com>2018-03-23 23:38:04 +0000
commit2f90bfba89ad7ac272dcb1cae064681fce98f1b9 (patch)
treed20207c6f632108c9609fee38d093966e6638068 /lib/hwasan/hwasan.cc
parent0691287972d44894b7fa3ca57af9c03133e45d26 (diff)
downloadcompiler-rt-2f90bfba89ad7ac272dcb1cae064681fce98f1b9.tar.gz
[HWASan] Port HWASan to Linux x86-64 (compiler-rt)
Summary: Porting HWASan to Linux x86-64, first of the three patches, compiler-rt part. The approach is similar to ARM case, trap signal is used to communicate memory tag check failure. int3 instruction is used to generate a signal, access parameters are stored in nop [eax + offset] instruction immediately following the int3 one Had to add HWASan init on malloc because, due to much less interceptors defined (most other sanitizers intercept much more and get initalized via one of those interceptors or don't care about malloc), HWASan was not initialized yet when libstdc++ was trying to allocate memory for its own fixed-size heap, which led to CHECK-fail in AllocateFromLocalPool. Also added the CHECK() failure handler with more detailed message and stack reporting. Reviewers: eugenis Subscribers: kubamracek, dberris, mgorny, kristof.beyls, delcypher, #sanitizers, llvm-commits Differential Revision: https://reviews.llvm.org/D44705 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@328385 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/hwasan/hwasan.cc')
-rw-r--r--lib/hwasan/hwasan.cc39
1 files changed, 31 insertions, 8 deletions
diff --git a/lib/hwasan/hwasan.cc b/lib/hwasan/hwasan.cc
index b2aadc4c8..225c34ba2 100644
--- a/lib/hwasan/hwasan.cc
+++ b/lib/hwasan/hwasan.cc
@@ -143,6 +143,14 @@ void PrintWarning(uptr pc, uptr bp) {
ReportInvalidAccess(&stack, 0);
}
+static void HWAsanCheckFailed(const char *file, int line, const char *cond,
+ u64 v1, u64 v2) {
+ Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
+ line, cond, (uptr)v1, (uptr)v2);
+ PRINT_CURRENT_STACK_CHECK();
+ Die();
+}
+
} // namespace __hwasan
// Interface.
@@ -160,6 +168,9 @@ void __hwasan_init() {
CacheBinaryName();
InitializeFlags();
+ // Install tool-specific callbacks in sanitizer_common.
+ SetCheckFailedCallback(HWAsanCheckFailed);
+
__sanitizer_set_report_path(common_flags()->log_path);
InitializeInterceptors();
@@ -240,11 +251,23 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
template<unsigned X>
__attribute__((always_inline))
-static void SigTrap() {
+static void SigTrap(uptr p) {
#if defined(__aarch64__)
- asm("brk %0\n\t" ::"n"(X));
-#elif defined(__x86_64__) || defined(__i386__)
- asm("ud2\n\t");
+ (void)p;
+ // 0x900 is added to do not interfere with the kernel use of lower values of
+ // brk immediate.
+ // FIXME: Add a constraint to put the pointer into x0, the same as x86 branch.
+ asm("brk %0\n\t" ::"n"(0x900 + X));
+#elif defined(__x86_64__)
+ // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
+ // total. The pointer is passed via rdi.
+ // 0x40 is added as a safeguard, to help distinguish our trap from others and
+ // to avoid 0 offsets in the command (otherwise it'll be reduced to a
+ // different nop command, the three bytes one).
+ asm volatile(
+ "int3\n"
+ "nopl %c0(%%rax)\n"
+ :: "n"(0x40 + X), "D"(p));
#else
// FIXME: not always sigill.
__builtin_trap();
@@ -261,8 +284,8 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
uptr ptr_raw = p & ~kAddressTagMask;
tag_t mem_tag = *(tag_t *)MEM_TO_SHADOW(ptr_raw);
if (UNLIKELY(ptr_tag != mem_tag)) {
- SigTrap<0x900 + 0x20 * (EA == ErrorAction::Recover) +
- 0x10 * (AT == AccessType::Store) + LogSize>();
+ SigTrap<0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + LogSize>(p);
if (EA == ErrorAction::Abort) __builtin_unreachable();
}
}
@@ -277,8 +300,8 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
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)) {
- SigTrap<0x900 + 0x20 * (EA == ErrorAction::Recover) +
- 0x10 * (AT == AccessType::Store) + 0xf>();
+ SigTrap<0x20 * (EA == ErrorAction::Recover) +
+ 0x10 * (AT == AccessType::Store) + 0xf>(p);
if (EA == ErrorAction::Abort) __builtin_unreachable();
}
}