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