(root)/
gcc-13.2.0/
libsanitizer/
interception/
interception.h
       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_APPLE &&      \
      20      !SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \
      21      !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)
      27  typedef __sanitizer::uptr    SIZE_T;
      28  typedef __sanitizer::sptr    SSIZE_T;
      29  typedef __sanitizer::sptr    PTRDIFF_T;
      30  typedef __sanitizer::s64     INTMAX_T;
      31  typedef __sanitizer::u64     UINTMAX_T;
      32  typedef __sanitizer::OFF_T   OFF_T;
      33  typedef __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_APPLE
      92  #include <sys/cdefs.h>  // For __DARWIN_ALIAS_C().
      93  
      94  // Just a pair of pointers.
      95  struct 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)) \
     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  
     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_FREEBSD || SANITIZER_NETBSD
     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")));
     143  #elif !SANITIZER_FUCHSIA
     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  
     152  #if SANITIZER_FUCHSIA
     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, ...)
     160  #elif !SANITIZER_APPLE
     161  # define PTR_TO_REAL(x) real_##x
     162  # define REAL(x) __interception::PTR_TO_REAL(x)
     163  # define FUNC_TYPE(x) x##_type
     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      }
     170  # define ASSIGN_REAL(dst, src) REAL(dst) = REAL(src)
     171  #else  // SANITIZER_APPLE
     172  # define REAL(x) x
     173  # define DECLARE_REAL(ret_type, func, ...) \
     174      extern "C" ret_type func(__VA_ARGS__);
     175  # define ASSIGN_REAL(x, y)
     176  #endif  // SANITIZER_APPLE
     177  
     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__);
     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__);
     187  #else
     188  # define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...)
     189  # define DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(ret_type, func, ...)
     190  #endif
     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.
     196  #if !SANITIZER_APPLE && !SANITIZER_FUCHSIA
     197  #  define DEFINE_REAL(ret_type, func, ...)            \
     198      typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
     199      namespace __interception {                        \
     200      FUNC_TYPE(func) PTR_TO_REAL(func);                \
     201      }
     202  #else
     203  # define DEFINE_REAL(ret_type, func, ...)
     204  #endif
     205  
     206  #if SANITIZER_FUCHSIA
     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  
     216  #elif !SANITIZER_APPLE
     217  
     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  
     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  
     229  #else  // SANITIZER_APPLE
     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  
     248  #if SANITIZER_WINDOWS
     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      } \
     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)
     266  typedef unsigned long long uptr;
     267  #else
     268  typedef unsigned long uptr;
     269  #endif  // _WIN64
     270  }  // namespace __interception
     271  
     272  #define INCLUDED_FROM_INTERCEPTION_LIB
     273  
     274  #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
     275      SANITIZER_SOLARIS
     276  
     277  # include "interception_linux.h"
     278  # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
     279  # define INTERCEPT_FUNCTION_VER(func, symver) \
     280      INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver)
     281  #elif SANITIZER_APPLE
     282  # include "interception_mac.h"
     283  # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
     284  # define INTERCEPT_FUNCTION_VER(func, symver) \
     285      INTERCEPT_FUNCTION_VER_MAC(func, symver)
     286  #elif SANITIZER_WINDOWS
     287  # include "interception_win.h"
     288  # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
     289  # define INTERCEPT_FUNCTION_VER(func, symver) \
     290      INTERCEPT_FUNCTION_VER_WIN(func, symver)
     291  #endif
     292  
     293  #undef INCLUDED_FROM_INTERCEPTION_LIB
     294  
     295  #endif  // INTERCEPTION_H