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 | |