xref: /src/contrib/llvm-project/compiler-rt/lib/interception/interception_linux.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
13a1720afSDimitry Andric //===-- interception_linux.cpp ----------------------------------*- C++ -*-===//
237dfff05SAndrew Turner //
38f3cadc2SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48f3cadc2SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
58f3cadc2SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
637dfff05SAndrew Turner //
737dfff05SAndrew Turner //===----------------------------------------------------------------------===//
837dfff05SAndrew Turner //
937dfff05SAndrew Turner // This file is a part of AddressSanitizer, an address sanity checker.
1037dfff05SAndrew Turner //
1137dfff05SAndrew Turner // Linux-specific interception methods.
1237dfff05SAndrew Turner //===----------------------------------------------------------------------===//
1337dfff05SAndrew Turner 
1458aabf08SAndrew Turner #include "interception.h"
1537dfff05SAndrew Turner 
16cdf4f305SDimitry Andric #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
17b60736ecSDimitry Andric     SANITIZER_SOLARIS
18cdf4f305SDimitry Andric 
19ca9211ecSDimitry Andric #include <dlfcn.h>   // for dlsym() and dlvsym()
2037dfff05SAndrew Turner 
218f3cadc2SDimitry Andric namespace __interception {
228f3cadc2SDimitry Andric 
23cdf4f305SDimitry Andric #if SANITIZER_NETBSD
StrCmp(const char * s1,const char * s2)248f3cadc2SDimitry Andric static int StrCmp(const char *s1, const char *s2) {
258f3cadc2SDimitry Andric   while (true) {
268f3cadc2SDimitry Andric     if (*s1 != *s2)
278f3cadc2SDimitry Andric       return false;
288f3cadc2SDimitry Andric     if (*s1 == 0)
298f3cadc2SDimitry Andric       return true;
308f3cadc2SDimitry Andric     s1++;
318f3cadc2SDimitry Andric     s2++;
328f3cadc2SDimitry Andric   }
338f3cadc2SDimitry Andric }
34cdf4f305SDimitry Andric #endif
35cdf4f305SDimitry Andric 
GetFuncAddr(const char * name,uptr trampoline)367fa27ce4SDimitry Andric static void *GetFuncAddr(const char *name, uptr trampoline) {
37cdf4f305SDimitry Andric #if SANITIZER_NETBSD
388f3cadc2SDimitry Andric   // FIXME: Find a better way to handle renames
398f3cadc2SDimitry Andric   if (StrCmp(name, "sigaction"))
408f3cadc2SDimitry Andric     name = "__sigaction14";
41cdf4f305SDimitry Andric #endif
428f3cadc2SDimitry Andric   void *addr = dlsym(RTLD_NEXT, name);
438f3cadc2SDimitry Andric   if (!addr) {
44cdf4f305SDimitry Andric     // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
45cdf4f305SDimitry Andric     // later in the library search order than the DSO that we are trying to
46cdf4f305SDimitry Andric     // intercept, which means that we cannot intercept this function. We still
47cdf4f305SDimitry Andric     // want the address of the real definition, though, so look it up using
48cdf4f305SDimitry Andric     // RTLD_DEFAULT.
498f3cadc2SDimitry Andric     addr = dlsym(RTLD_DEFAULT, name);
508f3cadc2SDimitry Andric 
518f3cadc2SDimitry Andric     // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
528f3cadc2SDimitry Andric     // We don't want to intercept the wrapper and have it point to itself.
537fa27ce4SDimitry Andric     if ((uptr)addr == trampoline)
548f3cadc2SDimitry Andric       addr = nullptr;
55cdf4f305SDimitry Andric   }
568f3cadc2SDimitry Andric   return addr;
578f3cadc2SDimitry Andric }
588f3cadc2SDimitry Andric 
InterceptFunction(const char * name,uptr * ptr_to_real,uptr func,uptr trampoline)598f3cadc2SDimitry Andric bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
607fa27ce4SDimitry Andric                        uptr trampoline) {
617fa27ce4SDimitry Andric   void *addr = GetFuncAddr(name, trampoline);
628f3cadc2SDimitry Andric   *ptr_to_real = (uptr)addr;
637fa27ce4SDimitry Andric   return addr && (func == trampoline);
6437dfff05SAndrew Turner }
658ef50bf3SDimitry Andric 
66b60736ecSDimitry Andric // dlvsym is a GNU extension supported by some other platforms.
67b60736ecSDimitry Andric #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
GetFuncAddr(const char * name,const char * ver)688f3cadc2SDimitry Andric static void *GetFuncAddr(const char *name, const char *ver) {
698f3cadc2SDimitry Andric   return dlvsym(RTLD_NEXT, name, ver);
708f3cadc2SDimitry Andric }
718f3cadc2SDimitry Andric 
InterceptFunction(const char * name,const char * ver,uptr * ptr_to_real,uptr func,uptr trampoline)728f3cadc2SDimitry Andric bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
737fa27ce4SDimitry Andric                        uptr func, uptr trampoline) {
748f3cadc2SDimitry Andric   void *addr = GetFuncAddr(name, ver);
758f3cadc2SDimitry Andric   *ptr_to_real = (uptr)addr;
767fa27ce4SDimitry Andric   return addr && (func == trampoline);
778ef50bf3SDimitry Andric }
78b60736ecSDimitry Andric #  endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
798ef50bf3SDimitry Andric 
8037dfff05SAndrew Turner }  // namespace __interception
8137dfff05SAndrew Turner 
82cdf4f305SDimitry Andric #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
83b60736ecSDimitry Andric         // SANITIZER_SOLARIS
84