asan_dll_thunk.cc revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1//===-- asan_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://code.google.com/p/address-sanitizer/issues/detail?id=209 for the 16// details. 17//===----------------------------------------------------------------------===// 18 19// Only compile this code when buidling asan_dll_thunk.lib 20// Using #ifdef rather than relying on Makefiles etc. 21// simplifies the build procedure. 22#ifdef ASAN_DLL_THUNK 23#include "asan_init_version.h" 24#include "sanitizer_common/sanitizer_interception.h" 25 26// ---------- Function interception helper functions and macros ----------- {{{1 27extern "C" { 28void *__stdcall GetModuleHandleA(const char *module_name); 29void *__stdcall GetProcAddress(void *module, const char *proc_name); 30void abort(); 31} 32 33static void *getRealProcAddressOrDie(const char *name) { 34 void *ret = GetProcAddress(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 void *wrapper = getRealProcAddressOrDie(main_function); \ 68 if (!__interception::OverrideFunction((uptr)dll_function, \ 69 (uptr)wrapper, 0)) \ 70 abort(); \ 71 FunctionInterceptor<__LINE__-1>::Execute(); \ 72 } \ 73 }; 74 75// Special case of hooks -- ASan own interface functions. Those are only called 76// after __asan_init, thus an empty implementation is sufficient. 77#define INTERFACE_FUNCTION(name) \ 78 extern "C" void name() { \ 79 volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \ 80 __debugbreak(); \ 81 } \ 82 INTERCEPT_WHEN_POSSIBLE(#name, name) 83 84// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. 85#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute 86 87// We can't define our own version of strlen etc. because that would lead to 88// link-time or even type mismatch errors. Instead, we can declare a function 89// just to be able to get its address. Me may miss the first few calls to the 90// functions since it can be called before __asan_init, but that would lead to 91// false negatives in the startup code before user's global initializers, which 92// isn't a big deal. 93#define INTERCEPT_LIBRARY_FUNCTION(name) \ 94 extern "C" void name(); \ 95 INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name) 96 97// Disable compiler warnings that show up if we declare our own version 98// of a compiler intrinsic (e.g. strlen). 99#pragma warning(disable: 4391) 100#pragma warning(disable: 4392) 101 102static void InterceptHooks(); 103// }}} 104 105// ---------- Function wrapping helpers ----------------------------------- {{{1 106#define WRAP_V_V(name) \ 107 extern "C" void name() { \ 108 typedef void (*fntype)(); \ 109 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 110 fn(); \ 111 } \ 112 INTERCEPT_WHEN_POSSIBLE(#name, name); 113 114#define WRAP_V_W(name) \ 115 extern "C" void name(void *arg) { \ 116 typedef void (*fntype)(void *arg); \ 117 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 118 fn(arg); \ 119 } \ 120 INTERCEPT_WHEN_POSSIBLE(#name, name); 121 122#define WRAP_V_WW(name) \ 123 extern "C" void name(void *arg1, void *arg2) { \ 124 typedef void (*fntype)(void *, void *); \ 125 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 126 fn(arg1, arg2); \ 127 } \ 128 INTERCEPT_WHEN_POSSIBLE(#name, name); 129 130#define WRAP_V_WWW(name) \ 131 extern "C" void name(void *arg1, void *arg2, void *arg3) { \ 132 typedef void *(*fntype)(void *, void *, void *); \ 133 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 134 fn(arg1, arg2, arg3); \ 135 } \ 136 INTERCEPT_WHEN_POSSIBLE(#name, name); 137 138#define WRAP_W_V(name) \ 139 extern "C" void *name() { \ 140 typedef void *(*fntype)(); \ 141 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 142 return fn(); \ 143 } \ 144 INTERCEPT_WHEN_POSSIBLE(#name, name); 145 146#define WRAP_W_W(name) \ 147 extern "C" void *name(void *arg) { \ 148 typedef void *(*fntype)(void *arg); \ 149 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 150 return fn(arg); \ 151 } \ 152 INTERCEPT_WHEN_POSSIBLE(#name, name); 153 154#define WRAP_W_WW(name) \ 155 extern "C" void *name(void *arg1, void *arg2) { \ 156 typedef void *(*fntype)(void *, void *); \ 157 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 158 return fn(arg1, arg2); \ 159 } \ 160 INTERCEPT_WHEN_POSSIBLE(#name, name); 161 162#define WRAP_W_WWW(name) \ 163 extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ 164 typedef void *(*fntype)(void *, void *, void *); \ 165 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 166 return fn(arg1, arg2, arg3); \ 167 } \ 168 INTERCEPT_WHEN_POSSIBLE(#name, name); 169 170#define WRAP_W_WWWW(name) \ 171 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ 172 typedef void *(*fntype)(void *, void *, void *, void *); \ 173 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 174 return fn(arg1, arg2, arg3, arg4); \ 175 } \ 176 INTERCEPT_WHEN_POSSIBLE(#name, name); 177 178#define WRAP_W_WWWWW(name) \ 179 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 180 void *arg5) { \ 181 typedef void *(*fntype)(void *, void *, void *, void *, void *); \ 182 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 183 return fn(arg1, arg2, arg3, arg4, arg5); \ 184 } \ 185 INTERCEPT_WHEN_POSSIBLE(#name, name); 186 187#define WRAP_W_WWWWWW(name) \ 188 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 189 void *arg5, void *arg6) { \ 190 typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ 191 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 192 return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ 193 } \ 194 INTERCEPT_WHEN_POSSIBLE(#name, name); 195// }}} 196 197// ----------------- ASan own interface functions -------------------- 198// Don't use the INTERFACE_FUNCTION machinery for this function as we actually 199// want to call it in the __asan_init interceptor. 200WRAP_W_V(__asan_should_detect_stack_use_after_return) 201 202extern "C" { 203 int __asan_option_detect_stack_use_after_return; 204 205 // Manually wrap __asan_init as we need to initialize 206 // __asan_option_detect_stack_use_after_return afterwards. 207 void __asan_init() { 208 typedef void (*fntype)(); 209 static fntype fn = 0; 210 // __asan_init is expected to be called by only one thread. 211 if (fn) return; 212 213 fn = (fntype)getRealProcAddressOrDie(__asan_init_name); 214 fn(); 215 __asan_option_detect_stack_use_after_return = 216 (__asan_should_detect_stack_use_after_return() != 0); 217 218 InterceptHooks(); 219 } 220} 221 222INTERFACE_FUNCTION(__asan_handle_no_return) 223 224INTERFACE_FUNCTION(__asan_report_store1) 225INTERFACE_FUNCTION(__asan_report_store2) 226INTERFACE_FUNCTION(__asan_report_store4) 227INTERFACE_FUNCTION(__asan_report_store8) 228INTERFACE_FUNCTION(__asan_report_store16) 229INTERFACE_FUNCTION(__asan_report_store_n) 230 231INTERFACE_FUNCTION(__asan_report_load1) 232INTERFACE_FUNCTION(__asan_report_load2) 233INTERFACE_FUNCTION(__asan_report_load4) 234INTERFACE_FUNCTION(__asan_report_load8) 235INTERFACE_FUNCTION(__asan_report_load16) 236INTERFACE_FUNCTION(__asan_report_load_n) 237 238INTERFACE_FUNCTION(__asan_memcpy); 239INTERFACE_FUNCTION(__asan_memset); 240INTERFACE_FUNCTION(__asan_memmove); 241 242INTERFACE_FUNCTION(__asan_register_globals) 243INTERFACE_FUNCTION(__asan_unregister_globals) 244 245INTERFACE_FUNCTION(__asan_before_dynamic_init) 246INTERFACE_FUNCTION(__asan_after_dynamic_init) 247 248INTERFACE_FUNCTION(__asan_poison_stack_memory) 249INTERFACE_FUNCTION(__asan_unpoison_stack_memory) 250 251INTERFACE_FUNCTION(__asan_poison_memory_region) 252INTERFACE_FUNCTION(__asan_unpoison_memory_region) 253 254INTERFACE_FUNCTION(__asan_get_current_fake_stack) 255INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) 256 257INTERFACE_FUNCTION(__asan_stack_malloc_0) 258INTERFACE_FUNCTION(__asan_stack_malloc_1) 259INTERFACE_FUNCTION(__asan_stack_malloc_2) 260INTERFACE_FUNCTION(__asan_stack_malloc_3) 261INTERFACE_FUNCTION(__asan_stack_malloc_4) 262INTERFACE_FUNCTION(__asan_stack_malloc_5) 263INTERFACE_FUNCTION(__asan_stack_malloc_6) 264INTERFACE_FUNCTION(__asan_stack_malloc_7) 265INTERFACE_FUNCTION(__asan_stack_malloc_8) 266INTERFACE_FUNCTION(__asan_stack_malloc_9) 267INTERFACE_FUNCTION(__asan_stack_malloc_10) 268 269INTERFACE_FUNCTION(__asan_stack_free_0) 270INTERFACE_FUNCTION(__asan_stack_free_1) 271INTERFACE_FUNCTION(__asan_stack_free_2) 272INTERFACE_FUNCTION(__asan_stack_free_4) 273INTERFACE_FUNCTION(__asan_stack_free_5) 274INTERFACE_FUNCTION(__asan_stack_free_6) 275INTERFACE_FUNCTION(__asan_stack_free_7) 276INTERFACE_FUNCTION(__asan_stack_free_8) 277INTERFACE_FUNCTION(__asan_stack_free_9) 278INTERFACE_FUNCTION(__asan_stack_free_10) 279 280INTERFACE_FUNCTION(__sanitizer_cov_module_init) 281 282// TODO(timurrrr): Add more interface functions on the as-needed basis. 283 284// ----------------- Memory allocation functions --------------------- 285WRAP_V_W(free) 286WRAP_V_WW(_free_dbg) 287 288WRAP_W_W(malloc) 289WRAP_W_WWWW(_malloc_dbg) 290 291WRAP_W_WW(calloc) 292WRAP_W_WWWWW(_calloc_dbg) 293WRAP_W_WWW(_calloc_impl) 294 295WRAP_W_WW(realloc) 296WRAP_W_WWW(_realloc_dbg) 297WRAP_W_WWW(_recalloc) 298 299WRAP_W_W(_msize) 300WRAP_W_W(_expand) 301WRAP_W_W(_expand_dbg) 302 303// TODO(timurrrr): Might want to add support for _aligned_* allocation 304// functions to detect a bit more bugs. Those functions seem to wrap malloc(). 305 306// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). 307 308INTERCEPT_LIBRARY_FUNCTION(atoi); 309INTERCEPT_LIBRARY_FUNCTION(atol); 310INTERCEPT_LIBRARY_FUNCTION(frexp); 311INTERCEPT_LIBRARY_FUNCTION(longjmp); 312INTERCEPT_LIBRARY_FUNCTION(memchr); 313INTERCEPT_LIBRARY_FUNCTION(memcmp); 314INTERCEPT_LIBRARY_FUNCTION(memcpy); 315INTERCEPT_LIBRARY_FUNCTION(memmove); 316INTERCEPT_LIBRARY_FUNCTION(memset); 317INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT 318INTERCEPT_LIBRARY_FUNCTION(strchr); 319INTERCEPT_LIBRARY_FUNCTION(strcmp); 320INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT 321INTERCEPT_LIBRARY_FUNCTION(strlen); 322INTERCEPT_LIBRARY_FUNCTION(strncat); 323INTERCEPT_LIBRARY_FUNCTION(strncmp); 324INTERCEPT_LIBRARY_FUNCTION(strncpy); 325INTERCEPT_LIBRARY_FUNCTION(strnlen); 326INTERCEPT_LIBRARY_FUNCTION(strtol); 327INTERCEPT_LIBRARY_FUNCTION(wcslen); 328 329// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS 330// is defined. 331void InterceptHooks() { 332 INTERCEPT_HOOKS(); 333} 334 335// We want to call __asan_init before C/C++ initializers/constructors are 336// executed, otherwise functions like memset might be invoked. 337// For some strange reason, merely linking in asan_preinit.cc doesn't work 338// as the callback is never called... Is link.exe doing something too smart? 339 340// In DLLs, the callbacks are expected to return 0, 341// otherwise CRT initialization fails. 342static int call_asan_init() { 343 __asan_init(); 344 return 0; 345} 346#pragma section(".CRT$XIB", long, read) // NOLINT 347__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; 348 349#endif // ASAN_DLL_THUNK 350