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