[ASan] Shared optimized callbacks implementation.

This change moves optimized callbacks from each .o file to compiler-rt. Instead of using code generation it uses direct assembly implementation. Please note that the 'or' version is not implemented and it will produce unresolved external if somehow 'or' version is requested.

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D114558
This commit is contained in:
Kirill Stoimenov 2021-11-17 22:39:48 +00:00
parent 017ef78549
commit f71c553a30
5 changed files with 265 additions and 12 deletions

View file

@ -24,6 +24,7 @@ set(ASAN_SOURCES
asan_premap_shadow.cpp
asan_report.cpp
asan_rtl.cpp
asan_rtl_x86_64.S
asan_shadow_setup.cpp
asan_stack.cpp
asan_stats.cpp

View file

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
// Asan interface list.
//===----------------------------------------------------------------------===//
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
INTERFACE_FUNCTION(__asan_address_is_poisoned)
INTERFACE_FUNCTION(__asan_after_dynamic_init)
@ -179,3 +180,36 @@ INTERFACE_FUNCTION(__asan_update_allocation_context)
INTERFACE_WEAK_FUNCTION(__asan_default_options)
INTERFACE_WEAK_FUNCTION(__asan_default_suppressions)
INTERFACE_WEAK_FUNCTION(__asan_on_error)
#if defined(__x86_64__)
# define ASAN_MEMORY_ACCESS_CALLBACK_ADD(s, reg, op) \
INTERFACE_FUNCTION(__asan_check_##op##_add_##s##_##reg)
# define ASAN_MEMORY_ACCESS_CALLBACKS_ADD(reg) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(1, reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(1, reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(2, reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(2, reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(4, reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(4, reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(8, reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(8, reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(16, reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD(16, reg, store)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RAX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RCX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RSI)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDI)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBP)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R8)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R9)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R12)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R13)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R14)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R15)
#endif // defined(__x86_64__)

View file

@ -0,0 +1,143 @@
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_asm.h"
#if defined(__x86_64__)
#include "sanitizer_common/sanitizer_platform.h"
.section .text
.file "asan_rtl_x86_64.S"
#define NAME(n, reg, op, s, i) n##_##op##_##i##_##s##_##reg
#define FNAME(reg, op, s, i) NAME(__asan_check, reg, op, s, i)
#define RLABEL(reg, op, s, i) NAME(.return, reg, op, s, i)
#define CLABEL(reg, op, s, i) NAME(.check, reg, op, s, i)
#define FLABEL(reg, op, s, i) NAME(.fail, reg, op, s, i)
#define BEGINF(reg, op, s, i) \
.globl FNAME(reg, op, s, i) ;\
ASM_TYPE_FUNCTION(FNAME(reg, op, s, i)) ;\
.cfi_startproc ;\
FNAME(reg, op, s, i): ;\
#define ENDF .cfi_endproc ;\
// Access check functions for 1,2 and 4 byte types, which require extra checks.
#define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \
mov %##reg,%r10 ;\
shr $0x3,%r10 ;\
movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\
test %r10d,%r10d ;\
jne CLABEL(reg, op, s, add) ;\
RLABEL(reg, op, s, add): ;\
retq ;\
#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, i) \
CLABEL(reg, op, 1, i): ;\
push %rcx ;\
mov %##reg,%rcx ;\
and $0x7,%ecx ;\
cmp %r10d,%ecx ;\
pop %rcx ;\
jl RLABEL(reg, op, 1, i);\
mov %##reg,%rdi ;\
jmp __asan_report_##op##1 ;\
#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, i) \
CLABEL(reg, op, 2, i): ;\
push %rcx ;\
mov %##reg,%rcx ;\
and $0x7,%ecx ;\
add $0x1,%ecx ;\
cmp %r10d,%ecx ;\
pop %rcx ;\
jl RLABEL(reg, op, 2, i);\
mov %##reg,%rdi ;\
jmp __asan_report_##op##2 ;\
#define ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, i) \
CLABEL(reg, op, 4, i): ;\
push %rcx ;\
mov %##reg,%rcx ;\
and $0x7,%ecx ;\
add $0x3,%ecx ;\
cmp %r10d,%ecx ;\
pop %rcx ;\
jl RLABEL(reg, op, 4, i);\
mov %##reg,%rdi ;\
jmp __asan_report_##op##4 ;\
#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, op) \
BEGINF(reg, op, 1, add) ;\
ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 1) ;\
ASAN_MEMORY_ACCESS_EXTRA_CHECK_1(reg, op, add) ;\
ENDF
#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, op) \
BEGINF(reg, op, 2, add) ;\
ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 2) ;\
ASAN_MEMORY_ACCESS_EXTRA_CHECK_2(reg, op, add) ;\
ENDF
#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, op) \
BEGINF(reg, op, 4, add) ;\
ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, 4) ;\
ASAN_MEMORY_ACCESS_EXTRA_CHECK_4(reg, op, add) ;\
ENDF
// Access check functions for 8 and 16 byte types: no extra checks required.
#define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \
mov %##reg,%r10 ;\
shr $0x3,%r10 ;\
##c $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\
jne FLABEL(reg, op, s, add) ;\
retq ;\
#define ASAN_MEMORY_ACCESS_FAIL(reg, op, s, i) \
FLABEL(reg, op, s, i): ;\
mov %##reg,%rdi ;\
jmp __asan_report_##op##s ;\
#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, op) \
BEGINF(reg, op, 8, add) ;\
ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 8, cmpb) ;\
ASAN_MEMORY_ACCESS_FAIL(reg, op, 8, add) ;\
ENDF
#define ASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, op) \
BEGINF(reg, op, 16, add) ;\
ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, 16, cmpw) ;\
ASAN_MEMORY_ACCESS_FAIL(reg, op, 16, add) ;\
ENDF
#define ASAN_MEMORY_ACCESS_CALLBACKS_ADD(reg) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_1(reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_2(reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_4(reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_8(reg, store) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, load) \
ASAN_MEMORY_ACCESS_CALLBACK_ADD_16(reg, store) \
// Instantiate all but R10 and R11 callbacks. We are using PLTSafe class with
// the intrinsic, which guarantees that the code generation will never emit
// R10 or R11 callback.
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RAX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RCX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDX)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RSI)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDI)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBP)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R8)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R9)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R12)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R13)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R14)
ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R15)
#endif

View file

@ -231,17 +231,8 @@ TEST(AddressSanitizer, ShadowRegionIsPoisonedTest) {
}
// Test __asan_load1 & friends.
TEST(AddressSanitizer, LoadStoreCallbacks) {
typedef void (*CB)(uptr p);
CB cb[2][5] = {
{
__asan_load1, __asan_load2, __asan_load4, __asan_load8, __asan_load16,
}, {
__asan_store1, __asan_store2, __asan_store4, __asan_store8,
__asan_store16,
}
};
typedef void (*CB)(uptr p);
static void TestLoadStoreCallbacks(CB cb[2][5]) {
uptr buggy_ptr;
__asan_test_only_reported_buggy_pointer = &buggy_ptr;
@ -271,3 +262,85 @@ TEST(AddressSanitizer, LoadStoreCallbacks) {
}
__asan_test_only_reported_buggy_pointer = 0;
}
TEST(AddressSanitizer, LoadStoreCallbacks) {
CB cb[2][5] = {{
__asan_load1,
__asan_load2,
__asan_load4,
__asan_load8,
__asan_load16,
},
{
__asan_store1,
__asan_store2,
__asan_store4,
__asan_store8,
__asan_store16,
}};
TestLoadStoreCallbacks(cb);
}
// clang-format off
#if defined(__x86_64__)
#define CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(s, reg, op) \
void CallAsanMemoryAccessAdd##reg##op##s(uptr address) { \
asm("push %%" #reg " \n" \
"mov %[x], %%" #reg " \n" \
"call __asan_check_" #op "_add_" #s "_" #reg "\n" \
"pop %%" #reg " \n" \
: \
: [x] "r"(address) \
: "r8", "rdi"); \
}
#define TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(reg) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(1, reg, load) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(1, reg, store) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(2, reg, load) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(2, reg, store) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(4, reg, load) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(4, reg, store) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(8, reg, load) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(8, reg, store) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(16, reg, load) \
CALL_ASAN_MEMORY_ACCESS_CALLBACK_ADD(16, reg, store) \
\
TEST(AddressSanitizer, LoadStoreCallbacksAddX86##reg) { \
CB cb[2][5] = {{ \
CallAsanMemoryAccessAdd##reg##load1, \
CallAsanMemoryAccessAdd##reg##load2, \
CallAsanMemoryAccessAdd##reg##load4, \
CallAsanMemoryAccessAdd##reg##load8, \
CallAsanMemoryAccessAdd##reg##load16, \
}, \
{ \
CallAsanMemoryAccessAdd##reg##store1, \
CallAsanMemoryAccessAdd##reg##store2, \
CallAsanMemoryAccessAdd##reg##store4, \
CallAsanMemoryAccessAdd##reg##store8, \
CallAsanMemoryAccessAdd##reg##store16, \
}}; \
TestLoadStoreCallbacks(cb); \
}
// Instantiate all but R10 and R11 callbacks. We are using PLTSafe class with
// the intrinsic, which guarantees that the code generation will never emit
// R10 or R11 callbacks.
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RAX)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBX)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RCX)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDX)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RSI)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RDI)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(RBP)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R8)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R9)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R12)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R13)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R14)
TEST_ASAN_MEMORY_ACCESS_CALLBACKS_ADD(R15)
#endif // defined(__x86_64__)
// clang-format on

View file

@ -1,5 +1,7 @@
// Check the presence of interface symbols in compiled file.
// RUN: %clangxx -x c++-header -o - -E %p/../../../../lib/asan/asan_interface.inc \
// RUN: | sed "s/INTERFACE_FUNCTION/\nINTERFACE_FUNCTION/g" > %t.asan_interface.inc
// RUN: %clangxx_asan -O2 %s -o %t.exe
// RUN: nm -D %t.exe | grep " [TWw] " \
// RUN: | grep -o "\(__asan_\|__ubsan_\|__sancov_\|__sanitizer_\)[^ ]*" \
@ -10,7 +12,7 @@
// RUN: > %t.exports
//
// RUN: grep -e "INTERFACE_\(WEAK_\)\?FUNCTION" \
// RUN: %p/../../../../lib/asan/asan_interface.inc \
// RUN: %t.asan_interface.inc \
// RUN: %p/../../../../lib/ubsan/ubsan_interface.inc \
// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface.inc \
// RUN: %p/../../../../lib/sanitizer_common/sanitizer_common_interface_posix.inc \