1 //===-- sanitizer_win_interception.cpp -------------------- --*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Windows-specific export surface to provide interception for parts of the 10 // runtime that are always statically linked, both for overriding user-defined 11 // functions as well as registering weak functions that the ASAN runtime should 12 // use over defaults. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "sanitizer_platform.h" 17 #if SANITIZER_WINDOWS 18 # include <stddef.h> 19 20 # include "interception/interception.h" 21 # include "sanitizer_addrhashmap.h" 22 # include "sanitizer_common.h" 23 # include "sanitizer_internal_defs.h" 24 # include "sanitizer_placement_new.h" 25 # include "sanitizer_win_immortalize.h" 26 # include "sanitizer_win_interception.h" 27 28 using namespace __sanitizer; 29 30 extern "C" void *__ImageBase; 31 32 namespace __sanitizer { 33 34 static uptr GetSanitizerDllExport(const char *export_name) { 35 const uptr function_address = 36 __interception::InternalGetProcAddress(&__ImageBase, export_name); 37 if (function_address == 0) { 38 Report("ERROR: Failed to find sanitizer DLL export '%s'\n", export_name); 39 CHECK("Failed to find sanitizer DLL export" && 0); 40 } 41 return function_address; 42 } 43 44 struct WeakCallbackList { 45 explicit constexpr WeakCallbackList(RegisterWeakFunctionCallback cb) 46 : callback(cb), next(nullptr) {} 47 48 static void *operator new(size_t size) { return InternalAlloc(size); } 49 50 static void operator delete(void *p) { InternalFree(p); } 51 52 RegisterWeakFunctionCallback callback; 53 WeakCallbackList *next; 54 }; 55 using WeakCallbackMap = AddrHashMap<WeakCallbackList *, 11>; 56 57 static WeakCallbackMap *GetWeakCallbackMap() { 58 return &immortalize<WeakCallbackMap>(); 59 } 60 61 void AddRegisterWeakFunctionCallback(uptr export_address, 62 RegisterWeakFunctionCallback cb) { 63 WeakCallbackMap::Handle h_find_or_create(GetWeakCallbackMap(), export_address, 64 false, true); 65 CHECK(h_find_or_create.exists()); 66 if (h_find_or_create.created()) { 67 *h_find_or_create = new WeakCallbackList(cb); 68 } else { 69 (*h_find_or_create)->next = new WeakCallbackList(cb); 70 } 71 } 72 73 static void RunWeakFunctionCallbacks(uptr export_address) { 74 WeakCallbackMap::Handle h_find(GetWeakCallbackMap(), export_address, false, 75 false); 76 if (!h_find.exists()) { 77 return; 78 } 79 80 WeakCallbackList *list = *h_find; 81 do { 82 list->callback(); 83 } while ((list = list->next)); 84 } 85 86 } // namespace __sanitizer 87 88 extern "C" __declspec(dllexport) bool __cdecl __sanitizer_override_function( 89 const char *export_name, const uptr user_function, 90 uptr *const old_user_function) { 91 CHECK(export_name); 92 CHECK(user_function); 93 94 const uptr sanitizer_function = GetSanitizerDllExport(export_name); 95 96 const bool function_overridden = __interception::OverrideFunction( 97 user_function, sanitizer_function, old_user_function); 98 if (!function_overridden) { 99 Report( 100 "ERROR: Failed to override local function at '%p' with sanitizer " 101 "function '%s'\n", 102 user_function, export_name); 103 CHECK("Failed to replace local function with sanitizer version." && 0); 104 } 105 106 return function_overridden; 107 } 108 109 extern "C" 110 __declspec(dllexport) bool __cdecl __sanitizer_override_function_by_addr( 111 const uptr source_function, const uptr target_function, 112 uptr *const old_target_function) { 113 CHECK(source_function); 114 CHECK(target_function); 115 116 const bool function_overridden = __interception::OverrideFunction( 117 target_function, source_function, old_target_function); 118 if (!function_overridden) { 119 Report( 120 "ERROR: Failed to override function at '%p' with function at " 121 "'%p'\n", 122 target_function, source_function); 123 CHECK("Failed to apply function override." && 0); 124 } 125 126 return function_overridden; 127 } 128 129 extern "C" 130 __declspec(dllexport) bool __cdecl __sanitizer_register_weak_function( 131 const char *export_name, const uptr user_function, 132 uptr *const old_user_function) { 133 CHECK(export_name); 134 CHECK(user_function); 135 136 const uptr sanitizer_function = GetSanitizerDllExport(export_name); 137 138 const bool function_overridden = __interception::OverrideFunction( 139 sanitizer_function, user_function, old_user_function); 140 if (!function_overridden) { 141 Report( 142 "ERROR: Failed to register local function at '%p' to be used in " 143 "place of sanitizer function '%s'\n.", 144 user_function, export_name); 145 CHECK("Failed to register weak function." && 0); 146 } 147 148 // Note that thread-safety of RunWeakFunctionCallbacks in InitializeFlags 149 // depends on __sanitizer_register_weak_functions being called during the 150 // loader lock. 151 RunWeakFunctionCallbacks(sanitizer_function); 152 153 return function_overridden; 154 } 155 156 #endif // SANITIZER_WINDOWS 157