1//===-- asan_win_dll_thunk.cc ---------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is a part of AddressSanitizer, an address sanity checker. 11// 12// This file defines a family of thunks that should be statically linked into 13// the DLLs that have ASan instrumentation in order to delegate the calls to the 14// shared runtime that lives in the main binary. 15// See https://github.com/google/sanitizers/issues/209 for the details. 16//===----------------------------------------------------------------------===// 17 18// Only compile this code when buidling asan_dll_thunk.lib 19// Using #ifdef rather than relying on Makefiles etc. 20// simplifies the build procedure. 21#ifdef ASAN_DLL_THUNK 22#include "asan_init_version.h" 23#include "interception/interception.h" 24 25// ---------- Function interception helper functions and macros ----------- {{{1 26extern "C" { 27void *__stdcall GetModuleHandleA(const char *module_name); 28void *__stdcall GetProcAddress(void *module, const char *proc_name); 29void abort(); 30} 31 32static uptr getRealProcAddressOrDie(const char *name) { 33 uptr ret = 34 __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); 35 if (!ret) 36 abort(); 37 return ret; 38} 39 40// We need to intercept some functions (e.g. ASan interface, memory allocator -- 41// let's call them "hooks") exported by the DLL thunk and forward the hooks to 42// the runtime in the main module. 43// However, we don't want to keep two lists of these hooks. 44// To avoid that, the list of hooks should be defined using the 45// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted 46// at once by calling INTERCEPT_HOOKS(). 47 48// Use macro+template magic to automatically generate the list of hooks. 49// Each hook at line LINE defines a template class with a static 50// FunctionInterceptor<LINE>::Execute() method intercepting the hook. 51// The default implementation of FunctionInterceptor<LINE> is to call 52// the Execute() method corresponding to the previous line. 53template<int LINE> 54struct FunctionInterceptor { 55 static void Execute() { FunctionInterceptor<LINE-1>::Execute(); } 56}; 57 58// There shouldn't be any hooks with negative definition line number. 59template<> 60struct FunctionInterceptor<0> { 61 static void Execute() {} 62}; 63 64#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ 65 template <> struct FunctionInterceptor<__LINE__> { \ 66 static void Execute() { \ 67 uptr wrapper = getRealProcAddressOrDie(main_function); \ 68 if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \ 69 abort(); \ 70 FunctionInterceptor<__LINE__ - 1>::Execute(); \ 71 } \ 72 }; 73 74// Special case of hooks -- ASan own interface functions. Those are only called 75// after __asan_init, thus an empty implementation is sufficient. 76#define INTERFACE_FUNCTION(name) \ 77 extern "C" __declspec(noinline) void name() { \ 78 volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ 79 __debugbreak(); \ 80 } \ 81 INTERCEPT_WHEN_POSSIBLE(#name, name) 82 83// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. 84#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute 85 86// We can't define our own version of strlen etc. because that would lead to 87// link-time or even type mismatch errors. Instead, we can declare a function 88// just to be able to get its address. Me may miss the first few calls to the 89// functions since it can be called before __asan_init, but that would lead to 90// false negatives in the startup code before user's global initializers, which 91// isn't a big deal. 92#define INTERCEPT_LIBRARY_FUNCTION(name) \ 93 extern "C" void name(); \ 94 INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name) 95 96// Disable compiler warnings that show up if we declare our own version 97// of a compiler intrinsic (e.g. strlen). 98#pragma warning(disable: 4391) 99#pragma warning(disable: 4392) 100 101static void InterceptHooks(); 102// }}} 103 104// ---------- Function wrapping helpers ----------------------------------- {{{1 105#define WRAP_V_V(name) \ 106 extern "C" void name() { \ 107 typedef void (*fntype)(); \ 108 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 109 fn(); \ 110 } \ 111 INTERCEPT_WHEN_POSSIBLE(#name, name); 112 113#define WRAP_V_W(name) \ 114 extern "C" void name(void *arg) { \ 115 typedef void (*fntype)(void *arg); \ 116 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 117 fn(arg); \ 118 } \ 119 INTERCEPT_WHEN_POSSIBLE(#name, name); 120 121#define WRAP_V_WW(name) \ 122 extern "C" void name(void *arg1, void *arg2) { \ 123 typedef void (*fntype)(void *, void *); \ 124 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 125 fn(arg1, arg2); \ 126 } \ 127 INTERCEPT_WHEN_POSSIBLE(#name, name); 128 129#define WRAP_V_WWW(name) \ 130 extern "C" void name(void *arg1, void *arg2, void *arg3) { \ 131 typedef void *(*fntype)(void *, void *, void *); \ 132 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 133 fn(arg1, arg2, arg3); \ 134 } \ 135 INTERCEPT_WHEN_POSSIBLE(#name, name); 136 137#define WRAP_W_V(name) \ 138 extern "C" void *name() { \ 139 typedef void *(*fntype)(); \ 140 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 141 return fn(); \ 142 } \ 143 INTERCEPT_WHEN_POSSIBLE(#name, name); 144 145#define WRAP_W_W(name) \ 146 extern "C" void *name(void *arg) { \ 147 typedef void *(*fntype)(void *arg); \ 148 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 149 return fn(arg); \ 150 } \ 151 INTERCEPT_WHEN_POSSIBLE(#name, name); 152 153#define WRAP_W_WW(name) \ 154 extern "C" void *name(void *arg1, void *arg2) { \ 155 typedef void *(*fntype)(void *, void *); \ 156 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 157 return fn(arg1, arg2); \ 158 } \ 159 INTERCEPT_WHEN_POSSIBLE(#name, name); 160 161#define WRAP_W_WWW(name) \ 162 extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ 163 typedef void *(*fntype)(void *, void *, void *); \ 164 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 165 return fn(arg1, arg2, arg3); \ 166 } \ 167 INTERCEPT_WHEN_POSSIBLE(#name, name); 168 169#define WRAP_W_WWWW(name) \ 170 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ 171 typedef void *(*fntype)(void *, void *, void *, void *); \ 172 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 173 return fn(arg1, arg2, arg3, arg4); \ 174 } \ 175 INTERCEPT_WHEN_POSSIBLE(#name, name); 176 177#define WRAP_W_WWWWW(name) \ 178 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 179 void *arg5) { \ 180 typedef void *(*fntype)(void *, void *, void *, void *, void *); \ 181 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 182 return fn(arg1, arg2, arg3, arg4, arg5); \ 183 } \ 184 INTERCEPT_WHEN_POSSIBLE(#name, name); 185 186#define WRAP_W_WWWWWW(name) \ 187 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 188 void *arg5, void *arg6) { \ 189 typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ 190 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 191 return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ 192 } \ 193 INTERCEPT_WHEN_POSSIBLE(#name, name); 194// }}} 195 196// ----------------- ASan own interface functions -------------------- 197// Don't use the INTERFACE_FUNCTION machinery for this function as we actually 198// want to call it in the __asan_init interceptor. 199WRAP_W_V(__asan_should_detect_stack_use_after_return) 200 201extern "C" { 202 int __asan_option_detect_stack_use_after_return; 203 204 // Manually wrap __asan_init as we need to initialize 205 // __asan_option_detect_stack_use_after_return afterwards. 206 void __asan_init() { 207 typedef void (*fntype)(); 208 static fntype fn = 0; 209 // __asan_init is expected to be called by only one thread. 210 if (fn) return; 211 212 fn = (fntype)getRealProcAddressOrDie("__asan_init"); 213 fn(); 214 __asan_option_detect_stack_use_after_return = 215 (__asan_should_detect_stack_use_after_return() != 0); 216 217 InterceptHooks(); 218 } 219} 220 221extern "C" void __asan_version_mismatch_check() { 222 // Do nothing. 223} 224 225INTERFACE_FUNCTION(__asan_handle_no_return) 226 227INTERFACE_FUNCTION(__asan_report_store1) 228INTERFACE_FUNCTION(__asan_report_store2) 229INTERFACE_FUNCTION(__asan_report_store4) 230INTERFACE_FUNCTION(__asan_report_store8) 231INTERFACE_FUNCTION(__asan_report_store16) 232INTERFACE_FUNCTION(__asan_report_store_n) 233 234INTERFACE_FUNCTION(__asan_report_load1) 235INTERFACE_FUNCTION(__asan_report_load2) 236INTERFACE_FUNCTION(__asan_report_load4) 237INTERFACE_FUNCTION(__asan_report_load8) 238INTERFACE_FUNCTION(__asan_report_load16) 239INTERFACE_FUNCTION(__asan_report_load_n) 240 241INTERFACE_FUNCTION(__asan_store1) 242INTERFACE_FUNCTION(__asan_store2) 243INTERFACE_FUNCTION(__asan_store4) 244INTERFACE_FUNCTION(__asan_store8) 245INTERFACE_FUNCTION(__asan_store16) 246INTERFACE_FUNCTION(__asan_storeN) 247 248INTERFACE_FUNCTION(__asan_load1) 249INTERFACE_FUNCTION(__asan_load2) 250INTERFACE_FUNCTION(__asan_load4) 251INTERFACE_FUNCTION(__asan_load8) 252INTERFACE_FUNCTION(__asan_load16) 253INTERFACE_FUNCTION(__asan_loadN) 254 255INTERFACE_FUNCTION(__asan_memcpy); 256INTERFACE_FUNCTION(__asan_memset); 257INTERFACE_FUNCTION(__asan_memmove); 258 259INTERFACE_FUNCTION(__asan_alloca_poison); 260INTERFACE_FUNCTION(__asan_allocas_unpoison); 261 262INTERFACE_FUNCTION(__asan_register_globals) 263INTERFACE_FUNCTION(__asan_unregister_globals) 264 265INTERFACE_FUNCTION(__asan_before_dynamic_init) 266INTERFACE_FUNCTION(__asan_after_dynamic_init) 267 268INTERFACE_FUNCTION(__asan_poison_stack_memory) 269INTERFACE_FUNCTION(__asan_unpoison_stack_memory) 270 271INTERFACE_FUNCTION(__asan_poison_memory_region) 272INTERFACE_FUNCTION(__asan_unpoison_memory_region) 273 274INTERFACE_FUNCTION(__asan_address_is_poisoned) 275INTERFACE_FUNCTION(__asan_region_is_poisoned) 276 277INTERFACE_FUNCTION(__asan_get_current_fake_stack) 278INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) 279 280INTERFACE_FUNCTION(__asan_stack_malloc_0) 281INTERFACE_FUNCTION(__asan_stack_malloc_1) 282INTERFACE_FUNCTION(__asan_stack_malloc_2) 283INTERFACE_FUNCTION(__asan_stack_malloc_3) 284INTERFACE_FUNCTION(__asan_stack_malloc_4) 285INTERFACE_FUNCTION(__asan_stack_malloc_5) 286INTERFACE_FUNCTION(__asan_stack_malloc_6) 287INTERFACE_FUNCTION(__asan_stack_malloc_7) 288INTERFACE_FUNCTION(__asan_stack_malloc_8) 289INTERFACE_FUNCTION(__asan_stack_malloc_9) 290INTERFACE_FUNCTION(__asan_stack_malloc_10) 291 292INTERFACE_FUNCTION(__asan_stack_free_0) 293INTERFACE_FUNCTION(__asan_stack_free_1) 294INTERFACE_FUNCTION(__asan_stack_free_2) 295INTERFACE_FUNCTION(__asan_stack_free_4) 296INTERFACE_FUNCTION(__asan_stack_free_5) 297INTERFACE_FUNCTION(__asan_stack_free_6) 298INTERFACE_FUNCTION(__asan_stack_free_7) 299INTERFACE_FUNCTION(__asan_stack_free_8) 300INTERFACE_FUNCTION(__asan_stack_free_9) 301INTERFACE_FUNCTION(__asan_stack_free_10) 302 303// FIXME: we might want to have a sanitizer_win_dll_thunk? 304INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container) 305INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address) 306INTERFACE_FUNCTION(__sanitizer_cov) 307INTERFACE_FUNCTION(__sanitizer_cov_dump) 308INTERFACE_FUNCTION(__sanitizer_cov_indir_call16) 309INTERFACE_FUNCTION(__sanitizer_cov_init) 310INTERFACE_FUNCTION(__sanitizer_cov_module_init) 311INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block) 312INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter) 313INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp) 314INTERFACE_FUNCTION(__sanitizer_cov_trace_switch) 315INTERFACE_FUNCTION(__sanitizer_cov_with_check) 316INTERFACE_FUNCTION(__sanitizer_get_allocated_size) 317INTERFACE_FUNCTION(__sanitizer_get_coverage_guards) 318INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes) 319INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size) 320INTERFACE_FUNCTION(__sanitizer_get_free_bytes) 321INTERFACE_FUNCTION(__sanitizer_get_heap_size) 322INTERFACE_FUNCTION(__sanitizer_get_ownership) 323INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs) 324INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage) 325INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes) 326INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) 327INTERFACE_FUNCTION(__sanitizer_print_stack_trace) 328INTERFACE_FUNCTION(__sanitizer_ptr_cmp) 329INTERFACE_FUNCTION(__sanitizer_ptr_sub) 330INTERFACE_FUNCTION(__sanitizer_report_error_summary) 331INTERFACE_FUNCTION(__sanitizer_reset_coverage) 332INTERFACE_FUNCTION(__sanitizer_get_number_of_counters) 333INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters) 334INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify) 335INTERFACE_FUNCTION(__sanitizer_set_death_callback) 336INTERFACE_FUNCTION(__sanitizer_set_report_path) 337INTERFACE_FUNCTION(__sanitizer_unaligned_load16) 338INTERFACE_FUNCTION(__sanitizer_unaligned_load32) 339INTERFACE_FUNCTION(__sanitizer_unaligned_load64) 340INTERFACE_FUNCTION(__sanitizer_unaligned_store16) 341INTERFACE_FUNCTION(__sanitizer_unaligned_store32) 342INTERFACE_FUNCTION(__sanitizer_unaligned_store64) 343INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container) 344 345// TODO(timurrrr): Add more interface functions on the as-needed basis. 346 347// ----------------- Memory allocation functions --------------------- 348WRAP_V_W(free) 349WRAP_V_WW(_free_dbg) 350 351WRAP_W_W(malloc) 352WRAP_W_WWWW(_malloc_dbg) 353 354WRAP_W_WW(calloc) 355WRAP_W_WWWWW(_calloc_dbg) 356WRAP_W_WWW(_calloc_impl) 357 358WRAP_W_WW(realloc) 359WRAP_W_WWW(_realloc_dbg) 360WRAP_W_WWW(_recalloc) 361 362WRAP_W_W(_msize) 363WRAP_W_W(_expand) 364WRAP_W_W(_expand_dbg) 365 366// TODO(timurrrr): Might want to add support for _aligned_* allocation 367// functions to detect a bit more bugs. Those functions seem to wrap malloc(). 368 369// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). 370 371INTERCEPT_LIBRARY_FUNCTION(atoi); 372INTERCEPT_LIBRARY_FUNCTION(atol); 373INTERCEPT_LIBRARY_FUNCTION(_except_handler3); 374 375// _except_handler4 checks -GS cookie which is different for each module, so we 376// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4). 377INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { 378 __asan_handle_no_return(); 379 return REAL(_except_handler4)(a, b, c, d); 380} 381 382INTERCEPT_LIBRARY_FUNCTION(frexp); 383INTERCEPT_LIBRARY_FUNCTION(longjmp); 384INTERCEPT_LIBRARY_FUNCTION(memchr); 385INTERCEPT_LIBRARY_FUNCTION(memcmp); 386INTERCEPT_LIBRARY_FUNCTION(memcpy); 387INTERCEPT_LIBRARY_FUNCTION(memmove); 388INTERCEPT_LIBRARY_FUNCTION(memset); 389INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT 390INTERCEPT_LIBRARY_FUNCTION(strchr); 391INTERCEPT_LIBRARY_FUNCTION(strcmp); 392INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT 393INTERCEPT_LIBRARY_FUNCTION(strcspn); 394INTERCEPT_LIBRARY_FUNCTION(strlen); 395INTERCEPT_LIBRARY_FUNCTION(strncat); 396INTERCEPT_LIBRARY_FUNCTION(strncmp); 397INTERCEPT_LIBRARY_FUNCTION(strncpy); 398INTERCEPT_LIBRARY_FUNCTION(strnlen); 399INTERCEPT_LIBRARY_FUNCTION(strpbrk); 400INTERCEPT_LIBRARY_FUNCTION(strspn); 401INTERCEPT_LIBRARY_FUNCTION(strstr); 402INTERCEPT_LIBRARY_FUNCTION(strtol); 403INTERCEPT_LIBRARY_FUNCTION(wcslen); 404 405// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS 406// is defined. 407void InterceptHooks() { 408 INTERCEPT_HOOKS(); 409 INTERCEPT_FUNCTION(_except_handler4); 410} 411 412// We want to call __asan_init before C/C++ initializers/constructors are 413// executed, otherwise functions like memset might be invoked. 414// For some strange reason, merely linking in asan_preinit.cc doesn't work 415// as the callback is never called... Is link.exe doing something too smart? 416 417// In DLLs, the callbacks are expected to return 0, 418// otherwise CRT initialization fails. 419static int call_asan_init() { 420 __asan_init(); 421 return 0; 422} 423#pragma section(".CRT$XIB", long, read) // NOLINT 424__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; 425 426#endif // ASAN_DLL_THUNK 427