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