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
28using namespace __sanitizer;
29
30extern "C" void *__ImageBase;
31
32namespace __sanitizer {
33
34static 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
44struct 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};
55using WeakCallbackMap = AddrHashMap<WeakCallbackList *, 11>;
56
57static WeakCallbackMap *GetWeakCallbackMap() {
58 return &immortalize<WeakCallbackMap>();
59}
60
61void 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
73static 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
88extern "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
109extern "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
129extern "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