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