asan_dll_thunk.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
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 "sanitizer_common/sanitizer_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 void *getRealProcAddressOrDie(const char *name) { 33 void *ret = GetProcAddress(GetModuleHandleA(0), name); 34 if (!ret) 35 abort(); 36 return ret; 37} 38 39// We need to intercept some functions (e.g. ASan interface, memory allocator -- 40// let's call them "hooks") exported by the DLL thunk and forward the hooks to 41// the runtime in the main module. 42// However, we don't want to keep two lists of these hooks. 43// To avoid that, the list of hooks should be defined using the 44// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted 45// at once by calling INTERCEPT_HOOKS(). 46 47// Use macro+template magic to automatically generate the list of hooks. 48// Each hook at line LINE defines a template class with a static 49// FunctionInterceptor<LINE>::Execute() method intercepting the hook. 50// The default implementation of FunctionInterceptor<LINE> is to call 51// the Execute() method corresponding to the previous line. 52template<int LINE> 53struct FunctionInterceptor { 54 static void Execute() { FunctionInterceptor<LINE-1>::Execute(); } 55}; 56 57// There shouldn't be any hooks with negative definition line number. 58template<> 59struct FunctionInterceptor<0> { 60 static void Execute() {} 61}; 62 63#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ 64 template<> struct FunctionInterceptor<__LINE__> { \ 65 static void Execute() { \ 66 void *wrapper = getRealProcAddressOrDie(main_function); \ 67 if (!__interception::OverrideFunction((uptr)dll_function, \ 68 (uptr)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" void name() { __debugbreak(); } \ 78 INTERCEPT_WHEN_POSSIBLE(#name, name) 79 80// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE. 81#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute 82 83// We can't define our own version of strlen etc. because that would lead to 84// link-time or even type mismatch errors. Instead, we can declare a function 85// just to be able to get its address. Me may miss the first few calls to the 86// functions since it can be called before __asan_init, but that would lead to 87// false negatives in the startup code before user's global initializers, which 88// isn't a big deal. 89#define INTERCEPT_LIBRARY_FUNCTION(name) \ 90 extern "C" void name(); \ 91 INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name) 92 93// Disable compiler warnings that show up if we declare our own version 94// of a compiler intrinsic (e.g. strlen). 95#pragma warning(disable: 4391) 96#pragma warning(disable: 4392) 97 98static void InterceptHooks(); 99// }}} 100 101// ---------- Function wrapping helpers ----------------------------------- {{{1 102#define WRAP_V_V(name) \ 103 extern "C" void name() { \ 104 typedef void (*fntype)(); \ 105 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 106 fn(); \ 107 } \ 108 INTERCEPT_WHEN_POSSIBLE(#name, name); 109 110#define WRAP_V_W(name) \ 111 extern "C" void name(void *arg) { \ 112 typedef void (*fntype)(void *arg); \ 113 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 114 fn(arg); \ 115 } \ 116 INTERCEPT_WHEN_POSSIBLE(#name, name); 117 118#define WRAP_V_WW(name) \ 119 extern "C" void name(void *arg1, void *arg2) { \ 120 typedef void (*fntype)(void *, void *); \ 121 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 122 fn(arg1, arg2); \ 123 } \ 124 INTERCEPT_WHEN_POSSIBLE(#name, name); 125 126#define WRAP_V_WWW(name) \ 127 extern "C" void name(void *arg1, void *arg2, void *arg3) { \ 128 typedef void *(*fntype)(void *, void *, void *); \ 129 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 130 fn(arg1, arg2, arg3); \ 131 } \ 132 INTERCEPT_WHEN_POSSIBLE(#name, name); 133 134#define WRAP_W_V(name) \ 135 extern "C" void *name() { \ 136 typedef void *(*fntype)(); \ 137 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 138 return fn(); \ 139 } \ 140 INTERCEPT_WHEN_POSSIBLE(#name, name); 141 142#define WRAP_W_W(name) \ 143 extern "C" void *name(void *arg) { \ 144 typedef void *(*fntype)(void *arg); \ 145 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 146 return fn(arg); \ 147 } \ 148 INTERCEPT_WHEN_POSSIBLE(#name, name); 149 150#define WRAP_W_WW(name) \ 151 extern "C" void *name(void *arg1, void *arg2) { \ 152 typedef void *(*fntype)(void *, void *); \ 153 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 154 return fn(arg1, arg2); \ 155 } \ 156 INTERCEPT_WHEN_POSSIBLE(#name, name); 157 158#define WRAP_W_WWW(name) \ 159 extern "C" void *name(void *arg1, void *arg2, void *arg3) { \ 160 typedef void *(*fntype)(void *, void *, void *); \ 161 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 162 return fn(arg1, arg2, arg3); \ 163 } \ 164 INTERCEPT_WHEN_POSSIBLE(#name, name); 165 166#define WRAP_W_WWWW(name) \ 167 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \ 168 typedef void *(*fntype)(void *, void *, void *, void *); \ 169 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 170 return fn(arg1, arg2, arg3, arg4); \ 171 } \ 172 INTERCEPT_WHEN_POSSIBLE(#name, name); 173 174#define WRAP_W_WWWWW(name) \ 175 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 176 void *arg5) { \ 177 typedef void *(*fntype)(void *, void *, void *, void *, void *); \ 178 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 179 return fn(arg1, arg2, arg3, arg4, arg5); \ 180 } \ 181 INTERCEPT_WHEN_POSSIBLE(#name, name); 182 183#define WRAP_W_WWWWWW(name) \ 184 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \ 185 void *arg5, void *arg6) { \ 186 typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \ 187 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \ 188 return fn(arg1, arg2, arg3, arg4, arg5, arg6); \ 189 } \ 190 INTERCEPT_WHEN_POSSIBLE(#name, name); 191// }}} 192 193// ----------------- ASan own interface functions -------------------- 194// Don't use the INTERFACE_FUNCTION machinery for this function as we actually 195// want to call it in the __asan_init interceptor. 196WRAP_W_V(__asan_should_detect_stack_use_after_return) 197 198extern "C" { 199 int __asan_option_detect_stack_use_after_return; 200 201 // Manually wrap __asan_init as we need to initialize 202 // __asan_option_detect_stack_use_after_return afterwards. 203 void __asan_init_v3() { 204 typedef void (*fntype)(); 205 static fntype fn = 0; 206 // __asan_init_v3 is expected to be called by only one thread. 207 if (fn) return; 208 209 fn = (fntype)getRealProcAddressOrDie("__asan_init_v3"); 210 fn(); 211 __asan_option_detect_stack_use_after_return = 212 (__asan_should_detect_stack_use_after_return() != 0); 213 214 InterceptHooks(); 215 } 216} 217 218INTERFACE_FUNCTION(__asan_handle_no_return) 219 220INTERFACE_FUNCTION(__asan_report_store1) 221INTERFACE_FUNCTION(__asan_report_store2) 222INTERFACE_FUNCTION(__asan_report_store4) 223INTERFACE_FUNCTION(__asan_report_store8) 224INTERFACE_FUNCTION(__asan_report_store16) 225INTERFACE_FUNCTION(__asan_report_store_n) 226 227INTERFACE_FUNCTION(__asan_report_load1) 228INTERFACE_FUNCTION(__asan_report_load2) 229INTERFACE_FUNCTION(__asan_report_load4) 230INTERFACE_FUNCTION(__asan_report_load8) 231INTERFACE_FUNCTION(__asan_report_load16) 232INTERFACE_FUNCTION(__asan_report_load_n) 233 234INTERFACE_FUNCTION(__asan_memcpy); 235INTERFACE_FUNCTION(__asan_memset); 236INTERFACE_FUNCTION(__asan_memmove); 237 238INTERFACE_FUNCTION(__asan_register_globals) 239INTERFACE_FUNCTION(__asan_unregister_globals) 240 241INTERFACE_FUNCTION(__asan_before_dynamic_init) 242INTERFACE_FUNCTION(__asan_after_dynamic_init) 243 244INTERFACE_FUNCTION(__asan_poison_stack_memory) 245INTERFACE_FUNCTION(__asan_unpoison_stack_memory) 246 247INTERFACE_FUNCTION(__asan_poison_memory_region) 248INTERFACE_FUNCTION(__asan_unpoison_memory_region) 249 250INTERFACE_FUNCTION(__asan_get_current_fake_stack) 251INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack) 252 253INTERFACE_FUNCTION(__asan_stack_malloc_0) 254INTERFACE_FUNCTION(__asan_stack_malloc_1) 255INTERFACE_FUNCTION(__asan_stack_malloc_2) 256INTERFACE_FUNCTION(__asan_stack_malloc_3) 257INTERFACE_FUNCTION(__asan_stack_malloc_4) 258INTERFACE_FUNCTION(__asan_stack_malloc_5) 259INTERFACE_FUNCTION(__asan_stack_malloc_6) 260INTERFACE_FUNCTION(__asan_stack_malloc_7) 261INTERFACE_FUNCTION(__asan_stack_malloc_8) 262INTERFACE_FUNCTION(__asan_stack_malloc_9) 263INTERFACE_FUNCTION(__asan_stack_malloc_10) 264 265INTERFACE_FUNCTION(__asan_stack_free_0) 266INTERFACE_FUNCTION(__asan_stack_free_1) 267INTERFACE_FUNCTION(__asan_stack_free_2) 268INTERFACE_FUNCTION(__asan_stack_free_4) 269INTERFACE_FUNCTION(__asan_stack_free_5) 270INTERFACE_FUNCTION(__asan_stack_free_6) 271INTERFACE_FUNCTION(__asan_stack_free_7) 272INTERFACE_FUNCTION(__asan_stack_free_8) 273INTERFACE_FUNCTION(__asan_stack_free_9) 274INTERFACE_FUNCTION(__asan_stack_free_10) 275 276// TODO(timurrrr): Add more interface functions on the as-needed basis. 277 278// ----------------- Memory allocation functions --------------------- 279WRAP_V_W(free) 280WRAP_V_WW(_free_dbg) 281 282WRAP_W_W(malloc) 283WRAP_W_WWWW(_malloc_dbg) 284 285WRAP_W_WW(calloc) 286WRAP_W_WWWWW(_calloc_dbg) 287WRAP_W_WWW(_calloc_impl) 288 289WRAP_W_WW(realloc) 290WRAP_W_WWW(_realloc_dbg) 291WRAP_W_WWW(_recalloc) 292 293WRAP_W_W(_msize) 294WRAP_W_W(_expand) 295WRAP_W_W(_expand_dbg) 296 297// TODO(timurrrr): Might want to add support for _aligned_* allocation 298// functions to detect a bit more bugs. Those functions seem to wrap malloc(). 299 300// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc). 301 302INTERCEPT_LIBRARY_FUNCTION(atoi); 303INTERCEPT_LIBRARY_FUNCTION(atol); 304INTERCEPT_LIBRARY_FUNCTION(frexp); 305INTERCEPT_LIBRARY_FUNCTION(longjmp); 306INTERCEPT_LIBRARY_FUNCTION(memchr); 307INTERCEPT_LIBRARY_FUNCTION(memcmp); 308INTERCEPT_LIBRARY_FUNCTION(memcpy); 309INTERCEPT_LIBRARY_FUNCTION(memmove); 310INTERCEPT_LIBRARY_FUNCTION(memset); 311INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT 312INTERCEPT_LIBRARY_FUNCTION(strchr); 313INTERCEPT_LIBRARY_FUNCTION(strcmp); 314INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT 315INTERCEPT_LIBRARY_FUNCTION(strlen); 316INTERCEPT_LIBRARY_FUNCTION(strncat); 317INTERCEPT_LIBRARY_FUNCTION(strncmp); 318INTERCEPT_LIBRARY_FUNCTION(strncpy); 319INTERCEPT_LIBRARY_FUNCTION(strnlen); 320INTERCEPT_LIBRARY_FUNCTION(strtol); 321INTERCEPT_LIBRARY_FUNCTION(wcslen); 322 323// Must be at the end of the file due to the way INTERCEPT_HOOKS is defined. 324void InterceptHooks() { 325 INTERCEPT_HOOKS(); 326} 327 328#endif // ASAN_DLL_THUNK 329