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