interception.h revision 360784
1//===-- interception.h ------------------------------------------*- 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// 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
17#include "sanitizer_common/sanitizer_internal_defs.h"
18
19#if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \
20    !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \
21    !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS
22# error "Interception doesn't work on this operating system."
23#endif
24
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)
27typedef __sanitizer::uptr    SIZE_T;
28typedef __sanitizer::sptr    SSIZE_T;
29typedef __sanitizer::sptr    PTRDIFF_T;
30typedef __sanitizer::s64     INTMAX_T;
31typedef __sanitizer::u64     UINTMAX_T;
32typedef __sanitizer::OFF_T   OFF_T;
33typedef __sanitizer::OFF64_T OFF64_T;
34
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
40//         your source file. See the notes below for cases when
41//         INTERCEPTOR_WITH_SUFFIX(...) should be used instead.
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
55// Notes: 1. Things may not work properly if macro INTERCEPTOR(...) {...} or
56//           DECLARE_REAL(...) are located inside namespaces.
57//        2. On Mac you can also use: "OVERRIDE_FUNCTION(foo, zoo)" to
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
62//           DECLARE_REAL(int, foo, const char *bar, double baz) in your
63//           source file (to define a pointer to overriden function).
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.
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.
78//
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
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.
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.
90
91#if SANITIZER_MAC
92#include <sys/cdefs.h>  // For __DARWIN_ALIAS_C().
93
94// Just a pair of pointers.
95struct interpose_substitution {
96  const __sanitizer::uptr replacement;
97  const __sanitizer::uptr original;
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)) \
104const 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)) \
114const 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
120# define WRAP(x) wrap_##x
121# define WRAPPER_NAME(x) "wrap_"#x
122# define INTERCEPTOR_ATTRIBUTE
123# define DECLARE_WRAPPER(ret_type, func, ...)
124
125#elif SANITIZER_WINDOWS
126# define WRAP(x) __asan_wrap_##x
127# define WRAPPER_NAME(x) "__asan_wrap_"#x
128# define INTERCEPTOR_ATTRIBUTE __declspec(dllexport)
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__);
133#elif SANITIZER_RTEMS
134# define WRAP(x) x
135# define WRAPPER_NAME(x) #x
136# define INTERCEPTOR_ATTRIBUTE
137# define DECLARE_WRAPPER(ret_type, func, ...)
138#elif SANITIZER_FREEBSD || SANITIZER_NETBSD
139# define WRAP(x) __interceptor_ ## x
140# define WRAPPER_NAME(x) "__interceptor_" #x
141# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
142// FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
143// priority than weak ones so weak aliases won't work for indirect calls
144// in position-independent (-fPIC / -fPIE) mode.
145# define DECLARE_WRAPPER(ret_type, func, ...) \
146     extern "C" ret_type func(__VA_ARGS__) \
147     __attribute__((alias("__interceptor_" #func), visibility("default")));
148#elif !SANITIZER_FUCHSIA
149# define WRAP(x) __interceptor_ ## x
150# define WRAPPER_NAME(x) "__interceptor_" #x
151# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
152# define DECLARE_WRAPPER(ret_type, func, ...) \
153    extern "C" ret_type func(__VA_ARGS__) \
154    __attribute__((weak, alias("__interceptor_" #func), visibility("default")));
155#endif
156
157#if SANITIZER_FUCHSIA
158// There is no general interception at all on Fuchsia.
159// Sanitizer runtimes just define functions directly to preempt them,
160// and have bespoke ways to access the underlying libc functions.
161# include <zircon/sanitizer.h>
162# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
163# define REAL(x) __unsanitized_##x
164# define DECLARE_REAL(ret_type, func, ...)
165#elif SANITIZER_RTEMS
166# define REAL(x) __real_ ## x
167# define DECLARE_REAL(ret_type, func, ...) \
168    extern "C" ret_type REAL(func)(__VA_ARGS__);
169#elif !SANITIZER_MAC
170# define PTR_TO_REAL(x) real_##x
171# define REAL(x) __interception::PTR_TO_REAL(x)
172# define FUNC_TYPE(x) x##_type
173
174# define DECLARE_REAL(ret_type, func, ...) \
175    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
176    namespace __interception { \
177      extern FUNC_TYPE(func) PTR_TO_REAL(func); \
178    }
179# define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src)
180#else  // SANITIZER_MAC
181# define REAL(x) x
182# define DECLARE_REAL(ret_type, func, ...) \
183    extern "C" ret_type func(__VA_ARGS__);
184# define ASSIGN_REAL(x, y)
185#endif  // SANITIZER_MAC
186
187#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
188# define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
189  DECLARE_REAL(ret_type, func, __VA_ARGS__) \
190  extern "C" ret_type WRAP(func)(__VA_ARGS__);
191// Declare an interceptor and its wrapper defined in a different translation
192// unit (ex. asm).
193# define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...)    \
194  extern "C" ret_type WRAP(func)(__VA_ARGS__); \
195  extern "C" ret_type func(__VA_ARGS__);
196#else
197# define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...)
198# define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...)
199#endif
200
201// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
202// macros does its job. In exceptional cases you may need to call REAL(foo)
203// without defining INTERCEPTOR(..., foo, ...). For example, if you override
204// foo with an interceptor for other function.
205#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
206# define DEFINE_REAL(ret_type, func, ...) \
207    typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
208    namespace __interception { \
209      FUNC_TYPE(func) PTR_TO_REAL(func); \
210    }
211#else
212# define DEFINE_REAL(ret_type, func, ...)
213#endif
214
215#if SANITIZER_FUCHSIA
216
217// We need to define the __interceptor_func name just to get
218// sanitizer_common/scripts/gen_dynamic_list.py to export func.
219// But we don't need to export __interceptor_func to get that.
220#define INTERCEPTOR(ret_type, func, ...)                                \
221  extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \
222      __interceptor_##func(__VA_ARGS__);                                \
223  extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__)
224
225#elif !SANITIZER_MAC
226
227#define INTERCEPTOR(ret_type, func, ...) \
228  DEFINE_REAL(ret_type, func, __VA_ARGS__) \
229  DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
230  extern "C" \
231  INTERCEPTOR_ATTRIBUTE \
232  ret_type WRAP(func)(__VA_ARGS__)
233
234// We don't need INTERCEPTOR_WITH_SUFFIX on non-Darwin for now.
235#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
236  INTERCEPTOR(ret_type, func, __VA_ARGS__)
237
238#else  // SANITIZER_MAC
239
240#define INTERCEPTOR_ZZZ(suffix, ret_type, func, ...) \
241  extern "C" ret_type func(__VA_ARGS__) suffix; \
242  extern "C" ret_type WRAP(func)(__VA_ARGS__); \
243  INTERPOSER(func); \
244  extern "C" INTERCEPTOR_ATTRIBUTE ret_type WRAP(func)(__VA_ARGS__)
245
246#define INTERCEPTOR(ret_type, func, ...) \
247  INTERCEPTOR_ZZZ(/*no symbol variants*/, ret_type, func, __VA_ARGS__)
248
249#define INTERCEPTOR_WITH_SUFFIX(ret_type, func, ...) \
250  INTERCEPTOR_ZZZ(__DARWIN_ALIAS_C(func), ret_type, func, __VA_ARGS__)
251
252// Override |overridee| with |overrider|.
253#define OVERRIDE_FUNCTION(overridee, overrider) \
254  INTERPOSER_2(overridee, WRAP(overrider))
255#endif
256
257#if SANITIZER_WINDOWS
258# define INTERCEPTOR_WINAPI(ret_type, func, ...) \
259    typedef ret_type (__stdcall *FUNC_TYPE(func))(__VA_ARGS__); \
260    namespace __interception { \
261      FUNC_TYPE(func) PTR_TO_REAL(func); \
262    } \
263    extern "C" \
264    INTERCEPTOR_ATTRIBUTE \
265    ret_type __stdcall WRAP(func)(__VA_ARGS__)
266#endif
267
268// ISO C++ forbids casting between pointer-to-function and pointer-to-object,
269// so we use casting via an integral type __interception::uptr,
270// assuming that system is POSIX-compliant. Using other hacks seem
271// challenging, as we don't even pass function type to
272// INTERCEPT_FUNCTION macro, only its name.
273namespace __interception {
274#if defined(_WIN64)
275typedef unsigned long long uptr;
276#else
277typedef unsigned long uptr;
278#endif  // _WIN64
279}  // namespace __interception
280
281#define INCLUDED_FROM_INTERCEPTION_LIB
282
283#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
284    SANITIZER_OPENBSD || SANITIZER_SOLARIS
285
286# include "interception_linux.h"
287# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
288# define INTERCEPT_FUNCTION_VER(func, symver) \
289    INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver)
290#elif SANITIZER_MAC
291# include "interception_mac.h"
292# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
293# define INTERCEPT_FUNCTION_VER(func, symver) \
294    INTERCEPT_FUNCTION_VER_MAC(func, symver)
295#elif SANITIZER_WINDOWS
296# include "interception_win.h"
297# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
298# define INTERCEPT_FUNCTION_VER(func, symver) \
299    INTERCEPT_FUNCTION_VER_WIN(func, symver)
300#endif
301
302#undef INCLUDED_FROM_INTERCEPTION_LIB
303
304#endif  // INTERCEPTION_H
305