13cab2bb3Spatrick //===-- interception_linux.cpp ----------------------------------*- C++ -*-===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is a part of AddressSanitizer, an address sanity checker.
103cab2bb3Spatrick //
113cab2bb3Spatrick // Linux-specific interception methods.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include "interception.h"
153cab2bb3Spatrick 
163cab2bb3Spatrick #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
17*d89ec533Spatrick     SANITIZER_SOLARIS
183cab2bb3Spatrick 
193cab2bb3Spatrick #include <dlfcn.h>   // for dlsym() and dlvsym()
203cab2bb3Spatrick 
213cab2bb3Spatrick namespace __interception {
223cab2bb3Spatrick 
233cab2bb3Spatrick #if SANITIZER_NETBSD
StrCmp(const char * s1,const char * s2)243cab2bb3Spatrick static int StrCmp(const char *s1, const char *s2) {
253cab2bb3Spatrick   while (true) {
263cab2bb3Spatrick     if (*s1 != *s2)
273cab2bb3Spatrick       return false;
283cab2bb3Spatrick     if (*s1 == 0)
293cab2bb3Spatrick       return true;
303cab2bb3Spatrick     s1++;
313cab2bb3Spatrick     s2++;
323cab2bb3Spatrick   }
333cab2bb3Spatrick }
343cab2bb3Spatrick #endif
353cab2bb3Spatrick 
GetFuncAddr(const char * name,uptr wrapper_addr)363cab2bb3Spatrick static void *GetFuncAddr(const char *name, uptr wrapper_addr) {
373cab2bb3Spatrick #if SANITIZER_NETBSD
383cab2bb3Spatrick   // FIXME: Find a better way to handle renames
393cab2bb3Spatrick   if (StrCmp(name, "sigaction"))
403cab2bb3Spatrick     name = "__sigaction14";
413cab2bb3Spatrick #endif
423cab2bb3Spatrick   void *addr = dlsym(RTLD_NEXT, name);
433cab2bb3Spatrick   if (!addr) {
443cab2bb3Spatrick     // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
453cab2bb3Spatrick     // later in the library search order than the DSO that we are trying to
463cab2bb3Spatrick     // intercept, which means that we cannot intercept this function. We still
473cab2bb3Spatrick     // want the address of the real definition, though, so look it up using
483cab2bb3Spatrick     // RTLD_DEFAULT.
493cab2bb3Spatrick     addr = dlsym(RTLD_DEFAULT, name);
503cab2bb3Spatrick 
513cab2bb3Spatrick     // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
523cab2bb3Spatrick     // We don't want to intercept the wrapper and have it point to itself.
533cab2bb3Spatrick     if ((uptr)addr == wrapper_addr)
543cab2bb3Spatrick       addr = nullptr;
553cab2bb3Spatrick   }
563cab2bb3Spatrick   return addr;
573cab2bb3Spatrick }
583cab2bb3Spatrick 
InterceptFunction(const char * name,uptr * ptr_to_real,uptr func,uptr wrapper)593cab2bb3Spatrick bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
603cab2bb3Spatrick                        uptr wrapper) {
613cab2bb3Spatrick   void *addr = GetFuncAddr(name, wrapper);
623cab2bb3Spatrick   *ptr_to_real = (uptr)addr;
633cab2bb3Spatrick   return addr && (func == wrapper);
643cab2bb3Spatrick }
653cab2bb3Spatrick 
66*d89ec533Spatrick // dlvsym is a GNU extension supported by some other platforms.
67*d89ec533Spatrick #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
GetFuncAddr(const char * name,const char * ver)683cab2bb3Spatrick static void *GetFuncAddr(const char *name, const char *ver) {
693cab2bb3Spatrick   return dlvsym(RTLD_NEXT, name, ver);
703cab2bb3Spatrick }
713cab2bb3Spatrick 
InterceptFunction(const char * name,const char * ver,uptr * ptr_to_real,uptr func,uptr wrapper)723cab2bb3Spatrick bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
733cab2bb3Spatrick                        uptr func, uptr wrapper) {
743cab2bb3Spatrick   void *addr = GetFuncAddr(name, ver);
753cab2bb3Spatrick   *ptr_to_real = (uptr)addr;
763cab2bb3Spatrick   return addr && (func == wrapper);
773cab2bb3Spatrick }
78*d89ec533Spatrick #endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
793cab2bb3Spatrick 
803cab2bb3Spatrick }  // namespace __interception
813cab2bb3Spatrick 
823cab2bb3Spatrick #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
83*d89ec533Spatrick         // SANITIZER_SOLARIS
84