forked from OSchip/llvm-project
[ASan Win] Simplify and improve the way we forward ASan interface calls from DLLs
Reviewed at http://reviews.llvm.org/D3848 llvm-svn: 209210
This commit is contained in:
parent
981ba24156
commit
e7894f3b14
|
@ -181,6 +181,7 @@ else()
|
|||
if (WIN32)
|
||||
add_compiler_rt_runtime(clang_rt.asan_dll_thunk-${arch} ${arch} STATIC
|
||||
SOURCES asan_dll_thunk.cc
|
||||
$<TARGET_OBJECTS:RTInterception.${arch}>
|
||||
CFLAGS ${ASAN_CFLAGS} -DASAN_DLL_THUNK
|
||||
DEFS ${ASAN_COMMON_DEFINITIONS})
|
||||
add_dependencies(asan clang_rt.asan_dll_thunk-${arch})
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// Using #ifdef rather than relying on Makefiles etc.
|
||||
// simplifies the build procedure.
|
||||
#ifdef ASAN_DLL_THUNK
|
||||
#include "sanitizer_common/sanitizer_interception.h"
|
||||
|
||||
// ----------------- Helper functions and macros --------------------- {{{1
|
||||
extern "C" {
|
||||
|
@ -115,7 +116,50 @@ static void *getRealProcAddressOrDie(const char *name) {
|
|||
}
|
||||
// }}}
|
||||
|
||||
// --------- Interface interception helper functions and macros ----------- {{{1
|
||||
// We need to intercept the ASan interface exported by the DLL thunk and forward
|
||||
// all the functions to the runtime in the main module.
|
||||
// However, we don't want to keep two lists of interface functions.
|
||||
// To avoid that, the list of interface functions should be defined using the
|
||||
// INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once
|
||||
// by calling INTERCEPT_ASAN_INTERFACE().
|
||||
|
||||
// Use macro+template magic to automatically generate the list of interface
|
||||
// functions. Each interface function at line LINE defines a template class
|
||||
// with a static InterfaceInteceptor<LINE>::Execute() method intercepting the
|
||||
// function. The default implementation of InterfaceInteceptor<LINE> is to call
|
||||
// the Execute() method corresponding to the previous line.
|
||||
template<int LINE>
|
||||
struct InterfaceInteceptor {
|
||||
static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); }
|
||||
};
|
||||
|
||||
// There shouldn't be any interface function with negative line number.
|
||||
template<>
|
||||
struct InterfaceInteceptor<0> {
|
||||
static void Execute() {}
|
||||
};
|
||||
|
||||
#define INTERFACE_FUNCTION(name) \
|
||||
extern "C" void name() { __debugbreak(); } \
|
||||
template<> struct InterfaceInteceptor<__LINE__> { \
|
||||
static void Execute() { \
|
||||
void *wrapper = getRealProcAddressOrDie(#name); \
|
||||
if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0)) \
|
||||
abort(); \
|
||||
InterfaceInteceptor<__LINE__-1>::Execute(); \
|
||||
} \
|
||||
};
|
||||
|
||||
// INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION.
|
||||
#define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute
|
||||
|
||||
static void InterceptASanInterface();
|
||||
// }}}
|
||||
|
||||
// ----------------- ASan own interface functions --------------------
|
||||
// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
|
||||
// want to call it in the __asan_init interceptor.
|
||||
WRAP_W_V(__asan_should_detect_stack_use_after_return)
|
||||
|
||||
extern "C" {
|
||||
|
@ -125,70 +169,75 @@ extern "C" {
|
|||
// __asan_option_detect_stack_use_after_return afterwards.
|
||||
void __asan_init_v3() {
|
||||
typedef void (*fntype)();
|
||||
static fntype fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
|
||||
static fntype fn = 0;
|
||||
if (fn) return;
|
||||
|
||||
fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
|
||||
fn();
|
||||
__asan_option_detect_stack_use_after_return =
|
||||
(__asan_should_detect_stack_use_after_return() != 0);
|
||||
|
||||
InterceptASanInterface();
|
||||
}
|
||||
}
|
||||
|
||||
WRAP_V_V(__asan_handle_no_return)
|
||||
INTERFACE_FUNCTION(__asan_handle_no_return)
|
||||
|
||||
WRAP_V_W(__asan_report_store1)
|
||||
WRAP_V_W(__asan_report_store2)
|
||||
WRAP_V_W(__asan_report_store4)
|
||||
WRAP_V_W(__asan_report_store8)
|
||||
WRAP_V_W(__asan_report_store16)
|
||||
WRAP_V_WW(__asan_report_store_n)
|
||||
INTERFACE_FUNCTION(__asan_report_store1)
|
||||
INTERFACE_FUNCTION(__asan_report_store2)
|
||||
INTERFACE_FUNCTION(__asan_report_store4)
|
||||
INTERFACE_FUNCTION(__asan_report_store8)
|
||||
INTERFACE_FUNCTION(__asan_report_store16)
|
||||
INTERFACE_FUNCTION(__asan_report_store_n)
|
||||
|
||||
WRAP_V_W(__asan_report_load1)
|
||||
WRAP_V_W(__asan_report_load2)
|
||||
WRAP_V_W(__asan_report_load4)
|
||||
WRAP_V_W(__asan_report_load8)
|
||||
WRAP_V_W(__asan_report_load16)
|
||||
WRAP_V_WW(__asan_report_load_n)
|
||||
INTERFACE_FUNCTION(__asan_report_load1)
|
||||
INTERFACE_FUNCTION(__asan_report_load2)
|
||||
INTERFACE_FUNCTION(__asan_report_load4)
|
||||
INTERFACE_FUNCTION(__asan_report_load8)
|
||||
INTERFACE_FUNCTION(__asan_report_load16)
|
||||
INTERFACE_FUNCTION(__asan_report_load_n)
|
||||
|
||||
WRAP_W_WWW(__asan_memcpy);
|
||||
WRAP_W_WWW(__asan_memset);
|
||||
WRAP_W_WWW(__asan_memmove);
|
||||
INTERFACE_FUNCTION(__asan_memcpy);
|
||||
INTERFACE_FUNCTION(__asan_memset);
|
||||
INTERFACE_FUNCTION(__asan_memmove);
|
||||
|
||||
WRAP_V_WW(__asan_register_globals)
|
||||
WRAP_V_WW(__asan_unregister_globals)
|
||||
INTERFACE_FUNCTION(__asan_register_globals)
|
||||
INTERFACE_FUNCTION(__asan_unregister_globals)
|
||||
|
||||
WRAP_V_W(__asan_before_dynamic_init)
|
||||
WRAP_V_V(__asan_after_dynamic_init)
|
||||
INTERFACE_FUNCTION(__asan_before_dynamic_init)
|
||||
INTERFACE_FUNCTION(__asan_after_dynamic_init)
|
||||
|
||||
WRAP_V_WW(__asan_poison_stack_memory)
|
||||
WRAP_V_WW(__asan_unpoison_stack_memory)
|
||||
INTERFACE_FUNCTION(__asan_poison_stack_memory)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
|
||||
|
||||
WRAP_V_WW(__asan_poison_memory_region)
|
||||
WRAP_V_WW(__asan_unpoison_memory_region)
|
||||
INTERFACE_FUNCTION(__asan_poison_memory_region)
|
||||
INTERFACE_FUNCTION(__asan_unpoison_memory_region)
|
||||
|
||||
WRAP_W_V(__asan_get_current_fake_stack)
|
||||
WRAP_W_WWWW(__asan_addr_is_in_fake_stack)
|
||||
INTERFACE_FUNCTION(__asan_get_current_fake_stack)
|
||||
INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
|
||||
|
||||
WRAP_W_WW(__asan_stack_malloc_0)
|
||||
WRAP_W_WW(__asan_stack_malloc_1)
|
||||
WRAP_W_WW(__asan_stack_malloc_2)
|
||||
WRAP_W_WW(__asan_stack_malloc_3)
|
||||
WRAP_W_WW(__asan_stack_malloc_4)
|
||||
WRAP_W_WW(__asan_stack_malloc_5)
|
||||
WRAP_W_WW(__asan_stack_malloc_6)
|
||||
WRAP_W_WW(__asan_stack_malloc_7)
|
||||
WRAP_W_WW(__asan_stack_malloc_8)
|
||||
WRAP_W_WW(__asan_stack_malloc_9)
|
||||
WRAP_W_WW(__asan_stack_malloc_10)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_3)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_malloc_10)
|
||||
|
||||
WRAP_V_WWW(__asan_stack_free_0)
|
||||
WRAP_V_WWW(__asan_stack_free_1)
|
||||
WRAP_V_WWW(__asan_stack_free_2)
|
||||
WRAP_V_WWW(__asan_stack_free_4)
|
||||
WRAP_V_WWW(__asan_stack_free_5)
|
||||
WRAP_V_WWW(__asan_stack_free_6)
|
||||
WRAP_V_WWW(__asan_stack_free_7)
|
||||
WRAP_V_WWW(__asan_stack_free_8)
|
||||
WRAP_V_WWW(__asan_stack_free_9)
|
||||
WRAP_V_WWW(__asan_stack_free_10)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_0)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_1)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_2)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_4)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_5)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_6)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_7)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_8)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_9)
|
||||
INTERFACE_FUNCTION(__asan_stack_free_10)
|
||||
|
||||
// TODO(timurrrr): Add more interface functions on the as-needed basis.
|
||||
|
||||
|
@ -216,4 +265,8 @@ WRAP_W_W(_expand_dbg)
|
|||
|
||||
// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
|
||||
|
||||
void InterceptASanInterface() {
|
||||
INTERCEPT_ASAN_INTERFACE();
|
||||
}
|
||||
|
||||
#endif // ASAN_DLL_THUNK
|
||||
|
|
|
@ -10,12 +10,13 @@ int test_function() {
|
|||
buffer[-1] = 42;
|
||||
// CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
|
||||
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
|
||||
// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: main {{.*}}dll_host.cc
|
||||
//
|
||||
// CHECK: [[ADDR]] is located 1 bytes to the left of 42-byte region
|
||||
// CHECK-LABEL: allocated by thread T0 here:
|
||||
// CHECK: malloc
|
||||
// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-9]]
|
||||
// CHECK: test_function {{.*}}dll_malloc_left_oob.cc:[[@LINE-10]]
|
||||
// CHECK-NEXT: main {{.*}}dll_host.cc
|
||||
// CHECK-LABEL: SUMMARY
|
||||
free(buffer);
|
||||
|
|
|
@ -7,21 +7,23 @@
|
|||
|
||||
extern "C" __declspec(dllexport)
|
||||
int test_function() {
|
||||
char *buffer = (char*)malloc(42);
|
||||
int *buffer = (int*)malloc(42);
|
||||
free(buffer);
|
||||
buffer[0] = 42;
|
||||
// CHECK: AddressSanitizer: heap-use-after-free on address [[ADDR:0x[0-9a-f]+]]
|
||||
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
|
||||
// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]]
|
||||
// CHECK: WRITE of size 4 at [[ADDR]] thread T0
|
||||
// CHECK-NEXT: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: main {{.*}}dll_host
|
||||
//
|
||||
// CHECK: [[ADDR]] is located 0 bytes inside of 42-byte region
|
||||
// CHECK-LABEL: freed by thread T0 here:
|
||||
// CHECK: free
|
||||
// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-9]]
|
||||
// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-10]]
|
||||
// CHECK-NEXT: main {{.*}}dll_host
|
||||
//
|
||||
// CHECK-LABEL: previously allocated by thread T0 here:
|
||||
// CHECK: malloc
|
||||
// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-14]]
|
||||
// CHECK: test_function {{.*}}dll_malloc_uaf.cc:[[@LINE-16]]
|
||||
// CHECK-NEXT: main {{.*}}dll_host
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,9 +12,10 @@ void noreturn_f() {
|
|||
_exit(1);
|
||||
// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
|
||||
// CHECK: WRITE of size 1 at [[ADDR]] thread T0
|
||||
// CHECK: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]]
|
||||
// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc:[[@LINE-4]]
|
||||
// CHECK-NEXT: test_function {{.*}}dll_noreturn.cc
|
||||
// CHECK-NEXT: main {{.*}}dll_host.cc
|
||||
//
|
||||
// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
|
||||
// CHECK-NEXT: noreturn_f {{.*}}dll_noreturn.cc
|
||||
// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable
|
||||
|
|
|
@ -25,9 +25,10 @@ int test_function() {
|
|||
should_crash(&buffer[96]);
|
||||
// CHECK: AddressSanitizer: use-after-poison on address [[ADDR:0x[0-9a-f]+]]
|
||||
// CHECK-NEXT: WRITE of size 1 at [[ADDR]] thread T0
|
||||
// CHECK: should_crash {{.*}}\dll_poison_unpoison.cc
|
||||
// CHECK-NEXT: should_crash {{.*}}\dll_poison_unpoison.cc
|
||||
// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc:[[@LINE-4]]
|
||||
// CHECK-NEXT: main
|
||||
//
|
||||
// CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
|
||||
// CHECK-NEXT: test_function {{.*}}\dll_poison_unpoison.cc
|
||||
// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable
|
||||
|
|
|
@ -18,8 +18,9 @@ int test_function() {
|
|||
*x = 42;
|
||||
// CHECK: AddressSanitizer: stack-use-after-return
|
||||
// CHECK: WRITE of size 1 at [[ADDR:.*]] thread T0
|
||||
// CHECK: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: test_function {{.*}}dll_stack_use_after_return.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: main
|
||||
//
|
||||
// CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
|
||||
// CHECK-NEXT: #0 {{.*}} foo {{.*}}dll_stack_use_after_return.cc
|
||||
// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable
|
||||
|
|
|
@ -12,9 +12,11 @@ DWORD WINAPI thread_proc(void *context) {
|
|||
stack_buffer[subscript] = 42;
|
||||
// CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]]
|
||||
// CHECK: WRITE of size 1 at [[ADDR]] thread T1
|
||||
// CHECK: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]]
|
||||
// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc:[[@LINE-3]]
|
||||
//
|
||||
// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame
|
||||
// CHECK: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc
|
||||
// CHECK-NEXT: thread_proc {{.*}}dll_thread_stack_array_left_oob.cc
|
||||
//
|
||||
// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue