|
14 | 14 | #ifndef INTERCEPTION_H
|
15 | 15 | #define INTERCEPTION_H
|
16 | 16 |
|
| 17 | +#include "sanitizer_common/sanitizer_asm.h" |
17 | 18 | #include "sanitizer_common/sanitizer_internal_defs.h"
|
18 | 19 |
|
19 | 20 | #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_APPLE && \
|
@@ -67,24 +68,50 @@ typedef __sanitizer::OFF64_T OFF64_T;
|
67 | 68 | // for more details). To intercept such functions you need to use the
|
68 | 69 | // INTERCEPTOR_WITH_SUFFIX(...) macro.
|
69 | 70 |
|
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 |
| 71 | +// How it works on Linux |
| 72 | +// --------------------- |
| 73 | +// |
| 74 | +// To replace system functions on Linux we just need to declare functions with |
| 75 | +// the same names in our library and then obtain the real function pointers |
73 | 76 | // 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 | 77 | //
|
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. |
| 78 | +// There is one complication: a user may also intercept some of the functions we |
| 79 | +// intercept. To allow for up to 3 interceptors (including ours) of a given |
| 80 | +// function "func", the interceptor implementation is in ___interceptor_func, |
| 81 | +// which is aliased by a weak function __interceptor_func, which in turn is |
| 82 | +// aliased (via a trampoline) by weak wrapper function "func". |
| 83 | +// |
| 84 | +// Most user interceptors should define a foreign interceptor as follows: |
| 85 | +// |
| 86 | +// - provide a non-weak function "func" that performs interception; |
| 87 | +// - if __interceptor_func exists, call it to perform the real functionality; |
| 88 | +// - if it does not exist, figure out the real function and call it instead. |
| 89 | +// |
| 90 | +// In rare cases, a foreign interceptor (of another dynamic analysis runtime) |
| 91 | +// may be defined as follows (on supported architectures): |
| 92 | +// |
| 93 | +// - provide a non-weak function __interceptor_func that performs interception; |
| 94 | +// - if ___interceptor_func exists, call it to perform the real functionality; |
| 95 | +// - if it does not exist, figure out the real function and call it instead; |
| 96 | +// - provide a weak function "func" that is an alias to __interceptor_func. |
| 97 | +// |
| 98 | +// With this protocol, sanitizer interceptors, foreign user interceptors, and |
| 99 | +// foreign interceptors of other dynamic analysis runtimes, or any combination |
| 100 | +// thereof, may co-exist simultaneously. |
| 101 | +// |
| 102 | +// How it works on Mac OS |
| 103 | +// ---------------------- |
| 104 | +// |
| 105 | +// This is not so on Mac OS, where the two-level namespace makes our replacement |
| 106 | +// functions invisible to other libraries. This may be overcomed using the |
| 107 | +// DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared libraries in |
| 108 | +// Chromium were noticed when doing so. |
| 109 | +// |
83 | 110 | // Instead we create a dylib containing a __DATA,__interpose section that
|
84 | 111 | // 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. |
| 112 | +// preloaded before an executable using DYLD_INSERT_LIBRARIES, it routes all the |
| 113 | +// calls to interposed functions done through stubs to the wrapper functions. |
| 114 | +// |
88 | 115 | // As it's decided at compile time which functions are to be intercepted on Mac,
|
89 | 116 | // INTERCEPT_FUNCTION() is effectively a no-op on this system.
|
90 | 117 |
|
@@ -131,20 +158,71 @@ const interpose_substitution substitution_##func_name[] \
|
131 | 158 | # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
|
132 | 159 | extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
|
133 | 160 | #elif !SANITIZER_FUCHSIA // LINUX, FREEBSD, NETBSD, SOLARIS
|
134 |
| -# define WRAP(x) __interceptor_ ## x |
135 |
| -# define TRAMPOLINE(x) WRAP(x) |
136 | 161 | # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
|
137 |
| -# if SANITIZER_FREEBSD || SANITIZER_NETBSD |
| 162 | +# if ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT |
| 163 | +// Weak aliases of weak aliases do not work, therefore we need to set up a |
| 164 | +// trampoline function. The function "func" is a weak alias to the trampoline |
| 165 | +// (so that we may check if "func" was overridden), which calls the weak |
| 166 | +// function __interceptor_func, which in turn aliases the actual interceptor |
| 167 | +// implementation ___interceptor_func: |
| 168 | +// |
| 169 | +// [wrapper "func": weak] --(alias)--> [TRAMPOLINE(func)] |
| 170 | +// | |
| 171 | +// +--------(tail call)-------+ |
| 172 | +// | |
| 173 | +// v |
| 174 | +// [__interceptor_func: weak] --(alias)--> [WRAP(func)] |
| 175 | +// |
| 176 | +// We use inline assembly to define most of this, because not all compilers |
| 177 | +// support functions with the "naked" attribute with every architecture. |
| 178 | +# define WRAP(x) ___interceptor_ ## x |
| 179 | +# define TRAMPOLINE(x) __interceptor_trampoline_ ## x |
| 180 | +# if SANITIZER_FREEBSD || SANITIZER_NETBSD |
138 | 181 | // FreeBSD's dynamic linker (incompliantly) gives non-weak symbols higher
|
139 | 182 | // priority than weak ones so weak aliases won't work for indirect calls
|
140 | 183 | // in position-independent (-fPIC / -fPIE) mode.
|
141 |
| -# define OVERRIDE_ATTRIBUTE |
142 |
| -# else // SANITIZER_FREEBSD || SANITIZER_NETBSD |
143 |
| -# define OVERRIDE_ATTRIBUTE __attribute__((weak)) |
144 |
| -# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD |
145 |
| -# define DECLARE_WRAPPER(ret_type, func, ...) \ |
146 |
| - extern "C" ret_type func(__VA_ARGS__) INTERCEPTOR_ATTRIBUTE \ |
147 |
| - OVERRIDE_ATTRIBUTE ALIAS(WRAP(func)); |
| 184 | +# define __ASM_WEAK_WRAPPER(func) |
| 185 | +# else |
| 186 | +# define __ASM_WEAK_WRAPPER(func) ".weak " #func "\n" |
| 187 | +# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD |
| 188 | +// Keep trampoline implementation in sync with sanitizer_common/sanitizer_asm.h |
| 189 | +# define DECLARE_WRAPPER(ret_type, func, ...) \ |
| 190 | + extern "C" ret_type func(__VA_ARGS__); \ |
| 191 | + extern "C" ret_type TRAMPOLINE(func)(__VA_ARGS__); \ |
| 192 | + extern "C" ret_type __interceptor_##func(__VA_ARGS__) \ |
| 193 | + INTERCEPTOR_ATTRIBUTE __attribute__((weak)) ALIAS(WRAP(func)); \ |
| 194 | + asm( \ |
| 195 | + ".text\n" \ |
| 196 | + __ASM_WEAK_WRAPPER(func) \ |
| 197 | + ".set " #func ", " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ |
| 198 | + ".globl " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ |
| 199 | + ".type " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", @function\n" \ |
| 200 | + SANITIZER_STRINGIFY(TRAMPOLINE(func)) ":\n" \ |
| 201 | + SANITIZER_STRINGIFY(CFI_STARTPROC) "\n" \ |
| 202 | + SANITIZER_STRINGIFY(ASM_TAIL_CALL) " __interceptor_" \ |
| 203 | + SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(func)) "\n" \ |
| 204 | + SANITIZER_STRINGIFY(CFI_ENDPROC) "\n" \ |
| 205 | + ".size " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \ |
| 206 | + ".-" SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \ |
| 207 | + ); |
| 208 | +# else // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT |
| 209 | +// Some architectures cannot implement efficient interceptor trampolines with |
| 210 | +// just a plain jump due to complexities of resolving a preemptible symbol. In |
| 211 | +// those cases, revert to just this scheme: |
| 212 | +// |
| 213 | +// [wrapper "func": weak] --(alias)--> [WRAP(func)] |
| 214 | +// |
| 215 | +# define WRAP(x) __interceptor_ ## x |
| 216 | +# define TRAMPOLINE(x) WRAP(x) |
| 217 | +# if SANITIZER_FREEBSD || SANITIZER_NETBSD |
| 218 | +# define __ATTRIBUTE_WEAK_WRAPPER |
| 219 | +# else |
| 220 | +# define __ATTRIBUTE_WEAK_WRAPPER __attribute__((weak)) |
| 221 | +# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD |
| 222 | +# define DECLARE_WRAPPER(ret_type, func, ...) \ |
| 223 | + extern "C" ret_type func(__VA_ARGS__) \ |
| 224 | + INTERCEPTOR_ATTRIBUTE __ATTRIBUTE_WEAK_WRAPPER ALIAS(WRAP(func)); |
| 225 | +# endif // ASM_INTERCEPTOR_TRAMPOLINE_SUPPORT |
148 | 226 | #endif
|
149 | 227 |
|
150 | 228 | #if SANITIZER_FUCHSIA
|
|
0 commit comments