]>
Commit | Line | Data |
---|---|---|
f35db108 WM |
1 | //===-- interception.h ------------------------------------------*- C++ -*-===// |
2 | // | |
b667dd70 ML |
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 | |
f35db108 WM |
6 | // |
7 | //===----------------------------------------------------------------------===// | |
8 | // | |
9 | // This file is a part of AddressSanitizer, an address sanity checker. | |
10 | // | |
11 | // Machinery for providing replacements/wrappers for system functions. | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
14 | #ifndef INTERCEPTION_H | |
15 | #define INTERCEPTION_H | |
16 | ||
eac97531 ML |
17 | #include "sanitizer_common/sanitizer_internal_defs.h" |
18 | ||
600413c4 | 19 | #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE && \ |
90e46074 L |
20 | !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \ |
21 | !SANITIZER_SOLARIS | |
22 | # error "Interception doesn't work on this operating system." | |
f35db108 WM |
23 | #endif |
24 | ||
e9772e16 KS |
25 | // These typedefs should be used only in the interceptor definitions to replace |
26 | // the standard system types (e.g. SSIZE_T instead of ssize_t) | |
ef1b3fda KS |
27 | typedef __sanitizer::uptr SIZE_T; |
28 | typedef __sanitizer::sptr SSIZE_T; | |
29 | typedef __sanitizer::sptr PTRDIFF_T; | |
30 | typedef __sanitizer::s64 INTMAX_T; | |
eac97531 | 31 | typedef __sanitizer::u64 UINTMAX_T; |
ef1b3fda KS |
32 | typedef __sanitizer::OFF_T OFF_T; |
33 | typedef __sanitizer::OFF64_T OFF64_T; | |
e9772e16 | 34 | |
f35db108 WM |
35 | // How to add an interceptor: |
36 | // Suppose you need to wrap/replace system function (generally, from libc): | |
37 | // int foo(const char *bar, double baz); | |
38 | // You'll need to: | |
39 | // 1) define INTERCEPTOR(int, foo, const char *bar, double baz) { ... } in | |
ef1b3fda KS |
40 | // your source file. See the notes below for cases when |
41 | // INTERCEPTOR_WITH_SUFFIX(...) should be used instead. | |
f35db108 WM |
42 | // 2) Call "INTERCEPT_FUNCTION(foo)" prior to the first call of "foo". |
43 | // INTERCEPT_FUNCTION(foo) evaluates to "true" iff the function was | |
44 | // intercepted successfully. | |
45 | // You can access original function by calling REAL(foo)(bar, baz). | |
46 | // By default, REAL(foo) will be visible only inside your interceptor, and if | |
47 | // you want to use it in other parts of RTL, you'll need to: | |
48 | // 3a) add DECLARE_REAL(int, foo, const char*, double) to a | |
49 | // header file. | |
50 | // However, if the call "INTERCEPT_FUNCTION(foo)" and definition for | |
51 | // INTERCEPTOR(..., foo, ...) are in different files, you'll instead need to: | |
52 | // 3b) add DECLARE_REAL_AND_INTERCEPTOR(int, foo, const char*, double) | |
53 | // to a header file. | |
54 | ||
ef1b3fda | 55 | // Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or |
f35db108 | 56 | // DECLARE_REAL(...) are located inside namespaces. |
ef1b3fda | 57 | // 2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to |
f35db108 WM |
58 | // effectively redirect calls from "foo" to "zoo". In this case |
59 | // you aren't required to implement | |
60 | // INTERCEPTOR(int, foo, const char *bar, double baz) {...} | |
61 | // but instead you'll have to add | |
ef1b3fda | 62 | // DECLARE_REAL(int, foo, const char *bar, double baz) in your |
f35db108 | 63 | // source file (to define a pointer to overriden function). |
ef1b3fda KS |
64 | // 3. Some Mac functions have symbol variants discriminated by |
65 | // additional suffixes, e.g. _$UNIX2003 (see | |
66 | // https://developer.apple.com/library/mac/#releasenotes/Darwin/SymbolVariantsRelNotes/index.html | |
67 | // for more details). To intercept such functions you need to use the | |
68 | // INTERCEPTOR_WITH_SUFFIX(...) macro. | |
f35db108 WM |
69 | |
70 | // How it works: | |
71 | // To replace system functions on Linux we just need to declare functions | |
72 | // with same names in our library and then obtain the real function pointers | |
73 | // using dlsym(). | |
74 | // There is one complication. A user may also intercept some of the functions | |
75 | // we intercept. To resolve this we declare our interceptors with __interceptor_ | |
76 | // prefix, and then make actual interceptors weak aliases to __interceptor_ | |
77 | // functions. | |
ef1b3fda | 78 | // |
f35db108 WM |
79 | // This is not so on Mac OS, where the two-level namespace makes |
80 | // our replacement functions invisible to other libraries. This may be overcomed | |
81 | // using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared | |
b4ab7d34 KS |
82 | // libraries in Chromium were noticed when doing so. |
83 | // Instead we create a dylib containing a __DATA,__interpose section that | |
84 | // associates library functions with their wrappers. When this dylib is | |
85 | // preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all | |
86 | // the calls to interposed functions done through stubs to the wrapper | |
87 | // functions. | |
ef1b3fda KS |
88 | // As it's decided at compile time which functions are to be intercepted on Mac, |
89 | // INTERCEPT_FUNCTION() is effectively a no-op on this system. | |
f35db108 | 90 | |
600413c4 | 91 | #if SANITIZER_APPLE |
ef1b3fda KS |
92 | #include <sys/cdefs.h> // For __DARWIN_ALIAS_C(). |
93 | ||
94 | // Just a pair of pointers. | |
95 | struct interpose_substitution { | |
10189819 MO |
96 | const __sanitizer::uptr replacement; |
97 | const __sanitizer::uptr original; | |
ef1b3fda KS |
98 | }; |
99 | ||
100 | // For a function foo() create a global pair of pointers { wrap_foo, foo } in | |
101 | // the __DATA,__interpose section. | |
102 | // As a result all the calls to foo() will be routed to wrap_foo() at runtime. | |
103 | #define INTERPOSER(func_name) __attribute__((used)) \ | |
104 | const interpose_substitution substitution_##func_name[] \ | |
105 | __attribute__((section("__DATA, __interpose"))) = { \ | |
106 | { reinterpret_cast<const uptr>(WRAP(func_name)), \ | |
107 | reinterpret_cast<const uptr>(func_name) } \ | |
108 | } | |
109 | ||
110 | // For a function foo() and a wrapper function bar() create a global pair | |
111 | // of pointers { bar, foo } in the __DATA,__interpose section. | |
112 | // As a result all the calls to foo() will be routed to bar() at runtime. | |
113 | #define INTERPOSER_2(func_name, wrapper_name) __attribute__((used)) \ | |
114 | const interpose_substitution substitution_##func_name[] \ | |
115 | __attribute__((section("__DATA, __interpose"))) = { \ | |
116 | { reinterpret_cast<const uptr>(wrapper_name), \ | |
117 | reinterpret_cast<const uptr>(func_name) } \ | |
118 | } | |
119 | ||
f35db108 WM |
120 | # define WRAP(x) wrap_##x |
121 | # define WRAPPER_NAME(x) "wrap_"#x | |
122 | # define INTERCEPTOR_ATTRIBUTE | |
123 | # define DECLARE_WRAPPER(ret_type, func, ...) | |
ef1b3fda | 124 | |
eac97531 | 125 | #elif SANITIZER_WINDOWS |
866e32ad KS |
126 | # define WRAP(x) __asan_wrap_##x |
127 | # define WRAPPER_NAME(x) "__asan_wrap_"#x | |
128 | # define INTERCEPTOR_ATTRIBUTE __declspec(dllexport) | |
ef1b3fda KS |
129 | # define DECLARE_WRAPPER(ret_type, func, ...) \ |
130 | extern "C" ret_type func(__VA_ARGS__); | |
131 | # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ | |
132 | extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); | |
eac97531 | 133 | #elif SANITIZER_FREEBSD || SANITIZER_NETBSD |
866e32ad KS |
134 | # define WRAP(x) __interceptor_ ## x |
135 | # define WRAPPER_NAME(x) "__interceptor_" #x | |
136 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | |
137 | // FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher | |
138 | // priority than weak ones so weak aliases won't work for indirect calls | |
139 | // in position-independent (-fPIC / -fPIE) mode. | |
140 | # define DECLARE_WRAPPER(ret_type, func, ...) \ | |
141 | extern "C" ret_type func(__VA_ARGS__) \ | |
142 | __attribute__((alias("__interceptor_" #func), visibility("default"))); | |
eac97531 | 143 | #elif !SANITIZER_FUCHSIA |
f35db108 WM |
144 | # define WRAP(x) __interceptor_ ## x |
145 | # define WRAPPER_NAME(x) "__interceptor_" #x | |
146 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | |
147 | # define DECLARE_WRAPPER(ret_type, func, ...) \ | |
148 | extern "C" ret_type func(__VA_ARGS__) \ | |
149 | __attribute__((weak, alias("__interceptor_" #func), visibility("default"))); | |
150 | #endif | |
151 | ||
eac97531 | 152 | #if SANITIZER_FUCHSIA |
5d3805fc JJ |
153 | // There is no general interception at all on Fuchsia. |
154 | // Sanitizer runtimes just define functions directly to preempt them, | |
155 | // and have bespoke ways to access the underlying libc functions. | |
156 | # include <zircon/sanitizer.h> | |
157 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) | |
158 | # define REAL(x) __unsanitized_##x | |
159 | # define DECLARE_REAL(ret_type, func, ...) | |
600413c4 | 160 | #elif !SANITIZER_APPLE |
f35db108 WM |
161 | # define PTR_TO_REAL(x) real_##x |
162 | # define REAL(x) __interception::PTR_TO_REAL(x) | |
eac97531 | 163 | # define FUNC_TYPE(x) x##_type |
f35db108 WM |
164 | |
165 | # define DECLARE_REAL(ret_type, func, ...) \ | |
166 | typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ | |
167 | namespace __interception { \ | |
168 | extern FUNC_TYPE(func) PTR_TO_REAL(func); \ | |
169 | } | |
10189819 | 170 | # define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src) |
600413c4 | 171 | #else // SANITIZER_APPLE |
f35db108 WM |
172 | # define REAL(x) x |
173 | # define DECLARE_REAL(ret_type, func, ...) \ | |
174 | extern "C" ret_type func(__VA_ARGS__); | |
10189819 | 175 | # define ASSIGN_REAL(x, y) |
600413c4 | 176 | #endif // SANITIZER_APPLE |
f35db108 | 177 | |
90e46074 L |
178 | #if !SANITIZER_FUCHSIA |
179 | # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \ | |
180 | DECLARE_REAL(ret_type, func, __VA_ARGS__) \ | |
181 | extern "C" ret_type WRAP(func)(__VA_ARGS__); | |
b667dd70 ML |
182 | // Declare an interceptor and its wrapper defined in a different translation |
183 | // unit (ex. asm). | |
184 | # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) \ | |
185 | extern "C" ret_type WRAP(func)(__VA_ARGS__); \ | |
186 | extern "C" ret_type func(__VA_ARGS__); | |
5d3805fc | 187 | #else |
b667dd70 ML |
188 | # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) |
189 | # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...) | |
5d3805fc | 190 | #endif |
f35db108 WM |
191 | |
192 | // Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR | |
193 | // macros does its job. In exceptional cases you may need to call REAL(foo) | |
194 | // without defining INTERCEPTOR(..., foo, ...). For example, if you override | |
195 | // foo with an interceptor for other function. | |
600413c4 | 196 | #if !SANITIZER_APPLE && !SANITIZER_FUCHSIA |
90e46074 | 197 | # define DEFINE_REAL(ret_type, func, ...) \ |
f35db108 | 198 | typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ |
90e46074 L |
199 | namespace __interception { \ |
200 | FUNC_TYPE(func) PTR_TO_REAL(func); \ | |
f35db108 WM |
201 | } |
202 | #else | |
203 | # define DEFINE_REAL(ret_type, func, ...) | |
204 | #endif | |
205 | ||
eac97531 | 206 | #if SANITIZER_FUCHSIA |
5d3805fc JJ |
207 | |
208 | // We need to define the __interceptor_func name just to get | |
209 | // sanitizer_common/scripts/gen_dynamic_list.py to export func. | |
210 | // But we don't need to export __interceptor_func to get that. | |
211 | #define INTERCEPTOR(ret_type, func, ...) \ | |
212 | extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \ | |
213 | __interceptor_##func(__VA_ARGS__); \ | |
214 | extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__) | |
215 | ||
600413c4 | 216 | #elif !SANITIZER_APPLE |
5d3805fc | 217 | |
f35db108 WM |
218 | #define INTERCEPTOR(ret_type, func, ...) \ |
219 | DEFINE_REAL(ret_type, func, __VA_ARGS__) \ | |
220 | DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \ | |
221 | extern "C" \ | |
222 | INTERCEPTOR_ATTRIBUTE \ | |
223 | ret_type WRAP(func)(__VA_ARGS__) | |
224 | ||
ef1b3fda KS |
225 | // We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now. |
226 | #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ | |
227 | INTERCEPTOR(ret_type, func, __VA_ARGS__) | |
228 | ||
600413c4 | 229 | #else // SANITIZER_APPLE |
ef1b3fda KS |
230 | |
231 | #define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \ | |
232 | extern "C" ret_type func(__VA_ARGS__) suffix; \ | |
233 | extern "C" ret_type WRAP(func)(__VA_ARGS__); \ | |
234 | INTERPOSER(func); \ | |
235 | extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__) | |
236 | ||
237 | #define INTERCEPTOR(ret_type, func, ...) \ | |
238 | INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__) | |
239 | ||
240 | #define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \ | |
241 | INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__) | |
242 | ||
243 | // Override |overridee| with |overrider|. | |
244 | #define OVERRIDE_FUNCTION(overridee, overrider) \ | |
245 | INTERPOSER_2(overridee, WRAP(overrider)) | |
246 | #endif | |
247 | ||
eac97531 | 248 | #if SANITIZER_WINDOWS |
f35db108 WM |
249 | # define INTERCEPTOR_WINAPI(ret_type, func, ...) \ |
250 | typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \ | |
251 | namespace __interception { \ | |
252 | FUNC_TYPE(func) PTR_TO_REAL(func); \ | |
253 | } \ | |
f35db108 WM |
254 | extern "C" \ |
255 | INTERCEPTOR_ATTRIBUTE \ | |
256 | ret_type __stdcall WRAP(func)(__VA_ARGS__) | |
257 | #endif | |
258 | ||
259 | // ISO C++ forbids casting between pointer-to-function and pointer-to-object, | |
260 | // so we use casting via an integral type __interception::uptr, | |
261 | // assuming that system is POSIX-compliant. Using other hacks seem | |
262 | // challenging, as we don't even pass function type to | |
263 | // INTERCEPT_FUNCTION macro, only its name. | |
264 | namespace __interception { | |
265 | #if defined(_WIN64) | |
3ca75cd5 | 266 | typedef unsigned long long uptr; |
f35db108 | 267 | #else |
3ca75cd5 | 268 | typedef unsigned long uptr; |
f35db108 WM |
269 | #endif // _WIN64 |
270 | } // namespace __interception | |
271 | ||
272 | #define INCLUDED_FROM_INTERCEPTION_LIB | |
273 | ||
eac97531 | 274 | #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ |
98f792ff | 275 | SANITIZER_SOLARIS |
eac97531 | 276 | |
f35db108 | 277 | # include "interception_linux.h" |
dee5ea7a | 278 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) |
df77f0e4 | 279 | # define INTERCEPT_FUNCTION_VER(func, symver) \ |
dee5ea7a | 280 | INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) |
600413c4 | 281 | #elif SANITIZER_APPLE |
f35db108 | 282 | # include "interception_mac.h" |
f35db108 | 283 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func) |
df77f0e4 KS |
284 | # define INTERCEPT_FUNCTION_VER(func, symver) \ |
285 | INTERCEPT_FUNCTION_VER_MAC(func, symver) | |
eac97531 | 286 | #elif SANITIZER_WINDOWS |
f35db108 WM |
287 | # include "interception_win.h" |
288 | # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func) | |
df77f0e4 KS |
289 | # define INTERCEPT_FUNCTION_VER(func, symver) \ |
290 | INTERCEPT_FUNCTION_VER_WIN(func, symver) | |
f35db108 WM |
291 | #endif |
292 | ||
293 | #undef INCLUDED_FROM_INTERCEPTION_LIB | |
294 | ||
295 | #endif // INTERCEPTION_H |