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 || \ 17*e8d8bef9SDimitry 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 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 3668d75effSDimitry Andric static void *GetFuncAddr(const char *name, uptr wrapper_addr) { 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. 5368d75effSDimitry Andric if ((uptr)addr == wrapper_addr) 5468d75effSDimitry Andric addr = nullptr; 5568d75effSDimitry Andric } 5668d75effSDimitry Andric return addr; 5768d75effSDimitry Andric } 5868d75effSDimitry Andric 5968d75effSDimitry Andric bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func, 6068d75effSDimitry Andric uptr wrapper) { 6168d75effSDimitry Andric void *addr = GetFuncAddr(name, wrapper); 6268d75effSDimitry Andric *ptr_to_real = (uptr)addr; 6368d75effSDimitry Andric return addr && (func == wrapper); 6468d75effSDimitry Andric } 6568d75effSDimitry Andric 66*e8d8bef9SDimitry Andric // dlvsym is a GNU extension supported by some other platforms. 67*e8d8bef9SDimitry Andric #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD 6868d75effSDimitry Andric static void *GetFuncAddr(const char *name, const char *ver) { 6968d75effSDimitry Andric return dlvsym(RTLD_NEXT, name, ver); 7068d75effSDimitry Andric } 7168d75effSDimitry Andric 7268d75effSDimitry Andric bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, 7368d75effSDimitry Andric uptr func, uptr wrapper) { 7468d75effSDimitry Andric void *addr = GetFuncAddr(name, ver); 7568d75effSDimitry Andric *ptr_to_real = (uptr)addr; 7668d75effSDimitry Andric return addr && (func == wrapper); 7768d75effSDimitry Andric } 78*e8d8bef9SDimitry 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 || 83*e8d8bef9SDimitry Andric // SANITIZER_SOLARIS 84