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