xref: /llvm-project/compiler-rt/lib/interception/interception_linux.cpp (revision d2ac2776021def69e9d0e64c9a958e0c361a919a)
1ebbce04cSNico Weber //===-- interception_linux.cpp ----------------------------------*- C++ -*-===//
2ebbce04cSNico Weber //
3ebbce04cSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ebbce04cSNico Weber // See https://llvm.org/LICENSE.txt for license information.
5ebbce04cSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ebbce04cSNico Weber //
7ebbce04cSNico Weber //===----------------------------------------------------------------------===//
8ebbce04cSNico Weber //
9ebbce04cSNico Weber // This file is a part of AddressSanitizer, an address sanity checker.
10ebbce04cSNico Weber //
11ebbce04cSNico Weber // Linux-specific interception methods.
12ebbce04cSNico Weber //===----------------------------------------------------------------------===//
13ebbce04cSNico Weber 
14ebbce04cSNico Weber #include "interception.h"
15ebbce04cSNico Weber 
16ebbce04cSNico Weber #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
1753065c54SDavid Carlier     SANITIZER_SOLARIS
18ebbce04cSNico Weber 
19ebbce04cSNico Weber #include <dlfcn.h>   // for dlsym() and dlvsym()
20ebbce04cSNico Weber 
21ebbce04cSNico Weber namespace __interception {
22ebbce04cSNico Weber 
23ebbce04cSNico Weber #if SANITIZER_NETBSD
StrCmp(const char * s1,const char * s2)24ebbce04cSNico Weber static int StrCmp(const char *s1, const char *s2) {
25ebbce04cSNico Weber   while (true) {
26ebbce04cSNico Weber     if (*s1 != *s2)
27ebbce04cSNico Weber       return false;
28ebbce04cSNico Weber     if (*s1 == 0)
29ebbce04cSNico Weber       return true;
30ebbce04cSNico Weber     s1++;
31ebbce04cSNico Weber     s2++;
32ebbce04cSNico Weber   }
33ebbce04cSNico Weber }
34ebbce04cSNico Weber #endif
35ebbce04cSNico Weber 
GetFuncAddr(const char * name,uptr trampoline)36*d2ac2776SMarco Elver static void *GetFuncAddr(const char *name, uptr trampoline) {
37ebbce04cSNico Weber #if SANITIZER_NETBSD
38ebbce04cSNico Weber   // FIXME: Find a better way to handle renames
39ebbce04cSNico Weber   if (StrCmp(name, "sigaction"))
40ebbce04cSNico Weber     name = "__sigaction14";
41ebbce04cSNico Weber #endif
42ebbce04cSNico Weber   void *addr = dlsym(RTLD_NEXT, name);
43ebbce04cSNico Weber   if (!addr) {
44ebbce04cSNico Weber     // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
45ebbce04cSNico Weber     // later in the library search order than the DSO that we are trying to
46ebbce04cSNico Weber     // intercept, which means that we cannot intercept this function. We still
47ebbce04cSNico Weber     // want the address of the real definition, though, so look it up using
48ebbce04cSNico Weber     // RTLD_DEFAULT.
49ebbce04cSNico Weber     addr = dlsym(RTLD_DEFAULT, name);
50ebbce04cSNico Weber 
51ebbce04cSNico Weber     // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
52ebbce04cSNico Weber     // We don't want to intercept the wrapper and have it point to itself.
53*d2ac2776SMarco Elver     if ((uptr)addr == trampoline)
54ebbce04cSNico Weber       addr = nullptr;
55ebbce04cSNico Weber   }
56ebbce04cSNico Weber   return addr;
57ebbce04cSNico Weber }
58ebbce04cSNico Weber 
InterceptFunction(const char * name,uptr * ptr_to_real,uptr func,uptr trampoline)59ebbce04cSNico Weber bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
60*d2ac2776SMarco Elver                        uptr trampoline) {
61*d2ac2776SMarco Elver   void *addr = GetFuncAddr(name, trampoline);
62ebbce04cSNico Weber   *ptr_to_real = (uptr)addr;
63*d2ac2776SMarco Elver   return addr && (func == trampoline);
64ebbce04cSNico Weber }
65ebbce04cSNico Weber 
667afdc89cSFangrui Song // dlvsym is a GNU extension supported by some other platforms.
677afdc89cSFangrui Song #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
GetFuncAddr(const char * name,const char * ver)68ebbce04cSNico Weber static void *GetFuncAddr(const char *name, const char *ver) {
69ebbce04cSNico Weber   return dlvsym(RTLD_NEXT, name, ver);
70ebbce04cSNico Weber }
71ebbce04cSNico Weber 
InterceptFunction(const char * name,const char * ver,uptr * ptr_to_real,uptr func,uptr trampoline)72ebbce04cSNico Weber bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
73*d2ac2776SMarco Elver                        uptr func, uptr trampoline) {
74ebbce04cSNico Weber   void *addr = GetFuncAddr(name, ver);
75ebbce04cSNico Weber   *ptr_to_real = (uptr)addr;
76*d2ac2776SMarco Elver   return addr && (func == trampoline);
77ebbce04cSNico Weber }
787afdc89cSFangrui Song #  endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
79ebbce04cSNico Weber 
80ebbce04cSNico Weber }  // namespace __interception
81ebbce04cSNico Weber 
82ebbce04cSNico Weber #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
8353065c54SDavid Carlier         // SANITIZER_SOLARIS
84