xref: /freebsd/contrib/llvm-project/compiler-rt/lib/interception/interception_linux.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1  //===-- interception_linux.cpp ----------------------------------*- 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  // Linux-specific interception methods.
12  //===----------------------------------------------------------------------===//
13  
14  #include "interception.h"
15  
16  #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
17      SANITIZER_SOLARIS
18  
19  #include <dlfcn.h>   // for dlsym() and dlvsym()
20  
21  namespace __interception {
22  
23  #if SANITIZER_NETBSD
StrCmp(const char * s1,const char * s2)24  static int StrCmp(const char *s1, const char *s2) {
25    while (true) {
26      if (*s1 != *s2)
27        return false;
28      if (*s1 == 0)
29        return true;
30      s1++;
31      s2++;
32    }
33  }
34  #endif
35  
GetFuncAddr(const char * name,uptr trampoline)36  static void *GetFuncAddr(const char *name, uptr trampoline) {
37  #if SANITIZER_NETBSD
38    // FIXME: Find a better way to handle renames
39    if (StrCmp(name, "sigaction"))
40      name = "__sigaction14";
41  #endif
42    void *addr = dlsym(RTLD_NEXT, name);
43    if (!addr) {
44      // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
45      // later in the library search order than the DSO that we are trying to
46      // intercept, which means that we cannot intercept this function. We still
47      // want the address of the real definition, though, so look it up using
48      // RTLD_DEFAULT.
49      addr = dlsym(RTLD_DEFAULT, name);
50  
51      // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
52      // We don't want to intercept the wrapper and have it point to itself.
53      if ((uptr)addr == trampoline)
54        addr = nullptr;
55    }
56    return addr;
57  }
58  
InterceptFunction(const char * name,uptr * ptr_to_real,uptr func,uptr trampoline)59  bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
60                         uptr trampoline) {
61    void *addr = GetFuncAddr(name, trampoline);
62    *ptr_to_real = (uptr)addr;
63    return addr && (func == trampoline);
64  }
65  
66  // dlvsym is a GNU extension supported by some other platforms.
67  #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
GetFuncAddr(const char * name,const char * ver)68  static void *GetFuncAddr(const char *name, const char *ver) {
69    return dlvsym(RTLD_NEXT, name, ver);
70  }
71  
InterceptFunction(const char * name,const char * ver,uptr * ptr_to_real,uptr func,uptr trampoline)72  bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
73                         uptr func, uptr trampoline) {
74    void *addr = GetFuncAddr(name, ver);
75    *ptr_to_real = (uptr)addr;
76    return addr && (func == trampoline);
77  }
78  #  endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
79  
80  }  // namespace __interception
81  
82  #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
83          // SANITIZER_SOLARIS
84