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