xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/interception/interception_linux.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
168d75effSDimitry Andric //===-- interception_linux.cpp ----------------------------------*- C++ -*-===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Linux-specific interception methods.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "interception.h"
1568d75effSDimitry Andric 
1668d75effSDimitry Andric #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
17e8d8bef9SDimitry Andric     SANITIZER_SOLARIS
1868d75effSDimitry Andric 
1968d75effSDimitry Andric #include <dlfcn.h>   // for dlsym() and dlvsym()
2068d75effSDimitry Andric 
2168d75effSDimitry Andric namespace __interception {
2268d75effSDimitry Andric 
2368d75effSDimitry Andric #if SANITIZER_NETBSD
StrCmp(const char * s1,const char * s2)2468d75effSDimitry Andric static int StrCmp(const char *s1, const char *s2) {
2568d75effSDimitry Andric   while (true) {
2668d75effSDimitry Andric     if (*s1 != *s2)
2768d75effSDimitry Andric       return false;
2868d75effSDimitry Andric     if (*s1 == 0)
2968d75effSDimitry Andric       return true;
3068d75effSDimitry Andric     s1++;
3168d75effSDimitry Andric     s2++;
3268d75effSDimitry Andric   }
3368d75effSDimitry Andric }
3468d75effSDimitry Andric #endif
3568d75effSDimitry Andric 
GetFuncAddr(const char * name,uptr trampoline)36*06c3fb27SDimitry Andric static void *GetFuncAddr(const char *name, uptr trampoline) {
3768d75effSDimitry Andric #if SANITIZER_NETBSD
3868d75effSDimitry Andric   // FIXME: Find a better way to handle renames
3968d75effSDimitry Andric   if (StrCmp(name, "sigaction"))
4068d75effSDimitry Andric     name = "__sigaction14";
4168d75effSDimitry Andric #endif
4268d75effSDimitry Andric   void *addr = dlsym(RTLD_NEXT, name);
4368d75effSDimitry Andric   if (!addr) {
4468d75effSDimitry Andric     // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
4568d75effSDimitry Andric     // later in the library search order than the DSO that we are trying to
4668d75effSDimitry Andric     // intercept, which means that we cannot intercept this function. We still
4768d75effSDimitry Andric     // want the address of the real definition, though, so look it up using
4868d75effSDimitry Andric     // RTLD_DEFAULT.
4968d75effSDimitry Andric     addr = dlsym(RTLD_DEFAULT, name);
5068d75effSDimitry Andric 
5168d75effSDimitry Andric     // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
5268d75effSDimitry Andric     // We don't want to intercept the wrapper and have it point to itself.
53*06c3fb27SDimitry Andric     if ((uptr)addr == trampoline)
5468d75effSDimitry Andric       addr = nullptr;
5568d75effSDimitry Andric   }
5668d75effSDimitry Andric   return addr;
5768d75effSDimitry Andric }
5868d75effSDimitry Andric 
InterceptFunction(const char * name,uptr * ptr_to_real,uptr func,uptr trampoline)5968d75effSDimitry Andric bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
60*06c3fb27SDimitry Andric                        uptr trampoline) {
61*06c3fb27SDimitry Andric   void *addr = GetFuncAddr(name, trampoline);
6268d75effSDimitry Andric   *ptr_to_real = (uptr)addr;
63*06c3fb27SDimitry Andric   return addr && (func == trampoline);
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
66e8d8bef9SDimitry Andric // dlvsym is a GNU extension supported by some other platforms.
67e8d8bef9SDimitry Andric #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
GetFuncAddr(const char * name,const char * ver)6868d75effSDimitry Andric static void *GetFuncAddr(const char *name, const char *ver) {
6968d75effSDimitry Andric   return dlvsym(RTLD_NEXT, name, ver);
7068d75effSDimitry Andric }
7168d75effSDimitry Andric 
InterceptFunction(const char * name,const char * ver,uptr * ptr_to_real,uptr func,uptr trampoline)7268d75effSDimitry Andric bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
73*06c3fb27SDimitry Andric                        uptr func, uptr trampoline) {
7468d75effSDimitry Andric   void *addr = GetFuncAddr(name, ver);
7568d75effSDimitry Andric   *ptr_to_real = (uptr)addr;
76*06c3fb27SDimitry Andric   return addr && (func == trampoline);
7768d75effSDimitry Andric }
78e8d8bef9SDimitry Andric #  endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
7968d75effSDimitry Andric 
8068d75effSDimitry Andric }  // namespace __interception
8168d75effSDimitry Andric 
8268d75effSDimitry Andric #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
83e8d8bef9SDimitry Andric         // SANITIZER_SOLARIS
84