mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[HWASAN] Add support for memory intrinsics
This is patch complements D55117 implementing __hwasan_mem* functions in runtime Differential revision: https://reviews.llvm.org/D55554 llvm-svn: 349730
This commit is contained in:
parent
fb2c74d98c
commit
d3bd614856
@ -7,6 +7,7 @@ set(HWASAN_RTL_SOURCES
|
||||
hwasan_dynamic_shadow.cc
|
||||
hwasan_interceptors.cc
|
||||
hwasan_linux.cc
|
||||
hwasan_memintrinsics.cc
|
||||
hwasan_poisoning.cc
|
||||
hwasan_report.cc
|
||||
hwasan_thread.cc
|
||||
|
@ -13,20 +13,20 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_mapping.h"
|
||||
#include "hwasan_checks.h"
|
||||
#include "hwasan_poisoning.h"
|
||||
#include "hwasan_report.h"
|
||||
#include "hwasan_thread.h"
|
||||
#include "hwasan_thread_list.h"
|
||||
#include "sanitizer_common/sanitizer_atomic.h"
|
||||
#include "sanitizer_common/sanitizer_common.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_flag_parser.h"
|
||||
#include "sanitizer_common/sanitizer_flags.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
#include "sanitizer_common/sanitizer_procmaps.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "sanitizer_common/sanitizer_stacktrace.h"
|
||||
#include "sanitizer_common/sanitizer_symbolizer.h"
|
||||
#include "sanitizer_common/sanitizer_stackdepot.h"
|
||||
#include "ubsan/ubsan_flags.h"
|
||||
#include "ubsan/ubsan_init.h"
|
||||
|
||||
@ -365,63 +365,6 @@ void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
|
||||
*p = x;
|
||||
}
|
||||
|
||||
template<unsigned X>
|
||||
__attribute__((always_inline))
|
||||
static void SigTrap(uptr p) {
|
||||
#if defined(__aarch64__)
|
||||
(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();
|
||||
#endif
|
||||
// __builtin_unreachable();
|
||||
}
|
||||
|
||||
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 *)MemToShadow(ptr_raw);
|
||||
if (UNLIKELY(ptr_tag != mem_tag)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + LogSize>(p);
|
||||
if (EA == ErrorAction::Abort) __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
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 *)MemToShadow(ptr_raw);
|
||||
tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz - 1);
|
||||
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
|
||||
if (UNLIKELY(ptr_tag != *t)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + 0xf>(p);
|
||||
if (EA == ErrorAction::Abort) __builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void __hwasan_loadN(uptr p, uptr sz) {
|
||||
CheckAddressSized<ErrorAction::Abort, AccessType::Load>(p, sz);
|
||||
}
|
||||
|
79
compiler-rt/lib/hwasan/hwasan_checks.h
Normal file
79
compiler-rt/lib/hwasan/hwasan_checks.h
Normal file
@ -0,0 +1,79 @@
|
||||
//===-- hwasan_checks.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of HWAddressSanitizer.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef HWASAN_CHECKS_H
|
||||
#define HWASAN_CHECKS_H
|
||||
|
||||
#include "hwasan_mapping.h"
|
||||
|
||||
namespace __hwasan {
|
||||
template <unsigned X>
|
||||
__attribute__((always_inline)) static void SigTrap(uptr p) {
|
||||
#if defined(__aarch64__)
|
||||
(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();
|
||||
#endif
|
||||
// __builtin_unreachable();
|
||||
}
|
||||
|
||||
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 *)MemToShadow(ptr_raw);
|
||||
if (UNLIKELY(ptr_tag != mem_tag)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + LogSize>(p);
|
||||
if (EA == ErrorAction::Abort)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
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 *)MemToShadow(ptr_raw);
|
||||
tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz - 1);
|
||||
for (tag_t *t = shadow_first; t <= shadow_last; ++t)
|
||||
if (UNLIKELY(ptr_tag != *t)) {
|
||||
SigTrap<0x20 * (EA == ErrorAction::Recover) +
|
||||
0x10 * (AT == AccessType::Store) + 0xf>(p);
|
||||
if (EA == ErrorAction::Abort)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
} // end namespace __hwasan
|
||||
|
||||
#endif // HWASAN_CHECKS_H
|
@ -194,6 +194,13 @@ void * __sanitizer_realloc(void *ptr, uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void * __sanitizer_malloc(uptr size);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memcpy(void *dst, const void *src, uptr size);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memset(void *s, int c, uptr n);
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void *__hwasan_memmove(void *dest, const void *src, uptr n);
|
||||
} // extern "C"
|
||||
|
||||
#endif // HWASAN_INTERFACE_INTERNAL_H
|
||||
|
45
compiler-rt/lib/hwasan/hwasan_memintrinsics.cc
Normal file
45
compiler-rt/lib/hwasan/hwasan_memintrinsics.cc
Normal file
@ -0,0 +1,45 @@
|
||||
//===-- hwasan_memintrinsics.cc ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file is a part of HWAddressSanitizer and contains HWASAN versions of
|
||||
/// memset, memcpy and memmove
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string.h>
|
||||
#include "hwasan.h"
|
||||
#include "hwasan_checks.h"
|
||||
#include "hwasan_flags.h"
|
||||
#include "hwasan_interface_internal.h"
|
||||
#include "sanitizer_common/sanitizer_libc.h"
|
||||
|
||||
using namespace __hwasan;
|
||||
|
||||
void *__hwasan_memset(void *block, int c, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(block), size);
|
||||
return memset(UntagPtr(block), c, size);
|
||||
}
|
||||
|
||||
void *__hwasan_memcpy(void *to, const void *from, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(to), size);
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
|
||||
reinterpret_cast<uptr>(from), size);
|
||||
return memcpy(UntagPtr(to), UntagPtr(from), size);
|
||||
}
|
||||
|
||||
void *__hwasan_memmove(void *to, const void *from, uptr size) {
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
|
||||
reinterpret_cast<uptr>(to), size);
|
||||
CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
|
||||
reinterpret_cast<uptr>(from), size);
|
||||
return memmove(UntagPtr(to), UntagPtr(from), size);
|
||||
}
|
37
compiler-rt/test/hwasan/TestCases/mem-intrinsics.c
Normal file
37
compiler-rt/test/hwasan/TestCases/mem-intrinsics.c
Normal file
@ -0,0 +1,37 @@
|
||||
// RUN: %clang_hwasan %s -DTEST_NO=1 -mllvm -hwasan-instrument-mem-intrinsics -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=WRITE
|
||||
// RUN: %clang_hwasan %s -DTEST_NO=2 -mllvm -hwasan-instrument-mem-intrinsics -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=READ
|
||||
// RUN: %clang_hwasan %s -DTEST_NO=3 -mllvm -hwasan-instrument-mem-intrinsics -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=WRITE
|
||||
// RUN: %clang_hwasan %s -DTEST_NO=2 -mllvm -hwasan-instrument-mem-intrinsics -o %t && not %env_hwasan_opts=halt_on_error=0 %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
|
||||
|
||||
// REQUIRES: stable-runtime
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
char Q[16];
|
||||
char P[16];
|
||||
#if TEST_NO == 1
|
||||
memset(Q, 0, 32);
|
||||
#elif TEST_NO == 2
|
||||
memmove(Q, Q + 16, 16);
|
||||
#elif TEST_NO == 3
|
||||
memcpy(Q, P, 32);
|
||||
#endif
|
||||
write(STDOUT_FILENO, "recovered\n", 10);
|
||||
// WRITE: ERROR: HWAddressSanitizer: tag-mismatch on address
|
||||
// WRITE: WRITE {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
|
||||
// WRITE: Memory tags around the buggy address (one tag corresponds to 16 bytes):
|
||||
// WRITE: =>{{.*}}[[MEM_TAG]]
|
||||
// WRITE-NOT: recovered
|
||||
|
||||
// READ: ERROR: HWAddressSanitizer: tag-mismatch on address
|
||||
// READ: READ {{.*}} tags: [[PTR_TAG:..]]/[[MEM_TAG:..]] (ptr/mem)
|
||||
// READ: Memory tags around the buggy address (one tag corresponds to 16 bytes):
|
||||
// READ: =>{{.*}}[[MEM_TAG]]
|
||||
// READ-NOT: recovered
|
||||
|
||||
// RECOVER: recovered
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user