xref: /llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_win_interception.cpp (revision 0265981b6ec0f46fc372897fef7f945d8f4625c2)
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