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