1*e8d8bef9SDimitry Andric //===-- FuzzerInterceptors.cpp --------------------------------------------===// 2*e8d8bef9SDimitry Andric // 3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*e8d8bef9SDimitry Andric // 7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8*e8d8bef9SDimitry Andric // Intercept certain libc functions to aid fuzzing. 9*e8d8bef9SDimitry Andric // Linked only when other RTs that define their own interceptors are not linked. 10*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 11*e8d8bef9SDimitry Andric 12*e8d8bef9SDimitry Andric #include "FuzzerPlatform.h" 13*e8d8bef9SDimitry Andric 14*e8d8bef9SDimitry Andric #if LIBFUZZER_LINUX 15*e8d8bef9SDimitry Andric 16*e8d8bef9SDimitry Andric #define GET_CALLER_PC() __builtin_return_address(0) 17*e8d8bef9SDimitry Andric 18*e8d8bef9SDimitry Andric #define PTR_TO_REAL(x) real_##x 19*e8d8bef9SDimitry Andric #define REAL(x) __interception::PTR_TO_REAL(x) 20*e8d8bef9SDimitry Andric #define FUNC_TYPE(x) x##_type 21*e8d8bef9SDimitry Andric #define DEFINE_REAL(ret_type, func, ...) \ 22*e8d8bef9SDimitry Andric typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ 23*e8d8bef9SDimitry Andric namespace __interception { \ 24*e8d8bef9SDimitry Andric FUNC_TYPE(func) PTR_TO_REAL(func); \ 25*e8d8bef9SDimitry Andric } 26*e8d8bef9SDimitry Andric 27*e8d8bef9SDimitry Andric #include <cassert> 28*e8d8bef9SDimitry Andric #include <cstdint> 29*e8d8bef9SDimitry Andric #include <dlfcn.h> // for dlsym() 30*e8d8bef9SDimitry Andric 31*e8d8bef9SDimitry Andric static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) { 32*e8d8bef9SDimitry Andric void *addr = dlsym(RTLD_NEXT, name); 33*e8d8bef9SDimitry Andric if (!addr) { 34*e8d8bef9SDimitry Andric // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is 35*e8d8bef9SDimitry Andric // later in the library search order than the DSO that we are trying to 36*e8d8bef9SDimitry Andric // intercept, which means that we cannot intercept this function. We still 37*e8d8bef9SDimitry Andric // want the address of the real definition, though, so look it up using 38*e8d8bef9SDimitry Andric // RTLD_DEFAULT. 39*e8d8bef9SDimitry Andric addr = dlsym(RTLD_DEFAULT, name); 40*e8d8bef9SDimitry Andric 41*e8d8bef9SDimitry Andric // In case `name' is not loaded, dlsym ends up finding the actual wrapper. 42*e8d8bef9SDimitry Andric // We don't want to intercept the wrapper and have it point to itself. 43*e8d8bef9SDimitry Andric if (reinterpret_cast<uintptr_t>(addr) == wrapper_addr) 44*e8d8bef9SDimitry Andric addr = nullptr; 45*e8d8bef9SDimitry Andric } 46*e8d8bef9SDimitry Andric return addr; 47*e8d8bef9SDimitry Andric } 48*e8d8bef9SDimitry Andric 49*e8d8bef9SDimitry Andric static int FuzzerInited = 0; 50*e8d8bef9SDimitry Andric static bool FuzzerInitIsRunning; 51*e8d8bef9SDimitry Andric 52*e8d8bef9SDimitry Andric static void fuzzerInit(); 53*e8d8bef9SDimitry Andric 54*e8d8bef9SDimitry Andric static void ensureFuzzerInited() { 55*e8d8bef9SDimitry Andric assert(!FuzzerInitIsRunning); 56*e8d8bef9SDimitry Andric if (!FuzzerInited) { 57*e8d8bef9SDimitry Andric fuzzerInit(); 58*e8d8bef9SDimitry Andric } 59*e8d8bef9SDimitry Andric } 60*e8d8bef9SDimitry Andric 61*e8d8bef9SDimitry Andric static int internal_strcmp_strncmp(const char *s1, const char *s2, bool strncmp, 62*e8d8bef9SDimitry Andric size_t n) { 63*e8d8bef9SDimitry Andric size_t i = 0; 64*e8d8bef9SDimitry Andric while (true) { 65*e8d8bef9SDimitry Andric if (strncmp) { 66*e8d8bef9SDimitry Andric if (i == n) 67*e8d8bef9SDimitry Andric break; 68*e8d8bef9SDimitry Andric i++; 69*e8d8bef9SDimitry Andric } 70*e8d8bef9SDimitry Andric unsigned c1 = *s1; 71*e8d8bef9SDimitry Andric unsigned c2 = *s2; 72*e8d8bef9SDimitry Andric if (c1 != c2) 73*e8d8bef9SDimitry Andric return (c1 < c2) ? -1 : 1; 74*e8d8bef9SDimitry Andric if (c1 == 0) 75*e8d8bef9SDimitry Andric break; 76*e8d8bef9SDimitry Andric s1++; 77*e8d8bef9SDimitry Andric s2++; 78*e8d8bef9SDimitry Andric } 79*e8d8bef9SDimitry Andric return 0; 80*e8d8bef9SDimitry Andric } 81*e8d8bef9SDimitry Andric 82*e8d8bef9SDimitry Andric static int internal_strncmp(const char *s1, const char *s2, size_t n) { 83*e8d8bef9SDimitry Andric return internal_strcmp_strncmp(s1, s2, true, n); 84*e8d8bef9SDimitry Andric } 85*e8d8bef9SDimitry Andric 86*e8d8bef9SDimitry Andric static int internal_strcmp(const char *s1, const char *s2) { 87*e8d8bef9SDimitry Andric return internal_strcmp_strncmp(s1, s2, false, 0); 88*e8d8bef9SDimitry Andric } 89*e8d8bef9SDimitry Andric 90*e8d8bef9SDimitry Andric static int internal_memcmp(const void *s1, const void *s2, size_t n) { 91*e8d8bef9SDimitry Andric const uint8_t *t1 = static_cast<const uint8_t *>(s1); 92*e8d8bef9SDimitry Andric const uint8_t *t2 = static_cast<const uint8_t *>(s2); 93*e8d8bef9SDimitry Andric for (size_t i = 0; i < n; ++i, ++t1, ++t2) 94*e8d8bef9SDimitry Andric if (*t1 != *t2) 95*e8d8bef9SDimitry Andric return *t1 < *t2 ? -1 : 1; 96*e8d8bef9SDimitry Andric return 0; 97*e8d8bef9SDimitry Andric } 98*e8d8bef9SDimitry Andric 99*e8d8bef9SDimitry Andric static size_t internal_strlen(const char *s) { 100*e8d8bef9SDimitry Andric size_t i = 0; 101*e8d8bef9SDimitry Andric while (s[i]) 102*e8d8bef9SDimitry Andric i++; 103*e8d8bef9SDimitry Andric return i; 104*e8d8bef9SDimitry Andric } 105*e8d8bef9SDimitry Andric 106*e8d8bef9SDimitry Andric static char *internal_strstr(const char *haystack, const char *needle) { 107*e8d8bef9SDimitry Andric // This is O(N^2), but we are not using it in hot places. 108*e8d8bef9SDimitry Andric size_t len1 = internal_strlen(haystack); 109*e8d8bef9SDimitry Andric size_t len2 = internal_strlen(needle); 110*e8d8bef9SDimitry Andric if (len1 < len2) 111*e8d8bef9SDimitry Andric return nullptr; 112*e8d8bef9SDimitry Andric for (size_t pos = 0; pos <= len1 - len2; pos++) { 113*e8d8bef9SDimitry Andric if (internal_memcmp(haystack + pos, needle, len2) == 0) 114*e8d8bef9SDimitry Andric return const_cast<char *>(haystack) + pos; 115*e8d8bef9SDimitry Andric } 116*e8d8bef9SDimitry Andric return nullptr; 117*e8d8bef9SDimitry Andric } 118*e8d8bef9SDimitry Andric 119*e8d8bef9SDimitry Andric extern "C" { 120*e8d8bef9SDimitry Andric 121*e8d8bef9SDimitry Andric // Weak hooks forward-declared to avoid dependency on 122*e8d8bef9SDimitry Andric // <sanitizer/common_interface_defs.h>. 123*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1, 124*e8d8bef9SDimitry Andric const void *s2, size_t n, int result); 125*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1, 126*e8d8bef9SDimitry Andric const char *s2, size_t n, int result); 127*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1, 128*e8d8bef9SDimitry Andric const char *s2, size_t n, int result); 129*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1, 130*e8d8bef9SDimitry Andric const char *s2, int result); 131*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1, 132*e8d8bef9SDimitry Andric const char *s2, int result); 133*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1, 134*e8d8bef9SDimitry Andric const char *s2, char *result); 135*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1, 136*e8d8bef9SDimitry Andric const char *s2, char *result); 137*e8d8bef9SDimitry Andric void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1, 138*e8d8bef9SDimitry Andric const void *s2, size_t len2, void *result); 139*e8d8bef9SDimitry Andric 140*e8d8bef9SDimitry Andric DEFINE_REAL(int, bcmp, const void *, const void *, size_t) 141*e8d8bef9SDimitry Andric DEFINE_REAL(int, memcmp, const void *, const void *, size_t) 142*e8d8bef9SDimitry Andric DEFINE_REAL(int, strncmp, const char *, const char *, size_t) 143*e8d8bef9SDimitry Andric DEFINE_REAL(int, strcmp, const char *, const char *) 144*e8d8bef9SDimitry Andric DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t) 145*e8d8bef9SDimitry Andric DEFINE_REAL(int, strcasecmp, const char *, const char *) 146*e8d8bef9SDimitry Andric DEFINE_REAL(char *, strstr, const char *, const char *) 147*e8d8bef9SDimitry Andric DEFINE_REAL(char *, strcasestr, const char *, const char *) 148*e8d8bef9SDimitry Andric DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t) 149*e8d8bef9SDimitry Andric 150*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int bcmp(const char *s1, const char *s2, size_t n) { 151*e8d8bef9SDimitry Andric if (!FuzzerInited) 152*e8d8bef9SDimitry Andric return internal_memcmp(s1, s2, n); 153*e8d8bef9SDimitry Andric int result = REAL(bcmp)(s1, s2, n); 154*e8d8bef9SDimitry Andric __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result); 155*e8d8bef9SDimitry Andric return result; 156*e8d8bef9SDimitry Andric } 157*e8d8bef9SDimitry Andric 158*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n) { 159*e8d8bef9SDimitry Andric if (!FuzzerInited) 160*e8d8bef9SDimitry Andric return internal_memcmp(s1, s2, n); 161*e8d8bef9SDimitry Andric int result = REAL(memcmp)(s1, s2, n); 162*e8d8bef9SDimitry Andric __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result); 163*e8d8bef9SDimitry Andric return result; 164*e8d8bef9SDimitry Andric } 165*e8d8bef9SDimitry Andric 166*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t n) { 167*e8d8bef9SDimitry Andric if (!FuzzerInited) 168*e8d8bef9SDimitry Andric return internal_strncmp(s1, s2, n); 169*e8d8bef9SDimitry Andric int result = REAL(strncmp)(s1, s2, n); 170*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result); 171*e8d8bef9SDimitry Andric return result; 172*e8d8bef9SDimitry Andric } 173*e8d8bef9SDimitry Andric 174*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) { 175*e8d8bef9SDimitry Andric if (!FuzzerInited) 176*e8d8bef9SDimitry Andric return internal_strcmp(s1, s2); 177*e8d8bef9SDimitry Andric int result = REAL(strcmp)(s1, s2); 178*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result); 179*e8d8bef9SDimitry Andric return result; 180*e8d8bef9SDimitry Andric } 181*e8d8bef9SDimitry Andric 182*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2, size_t n) { 183*e8d8bef9SDimitry Andric ensureFuzzerInited(); 184*e8d8bef9SDimitry Andric int result = REAL(strncasecmp)(s1, s2, n); 185*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result); 186*e8d8bef9SDimitry Andric return result; 187*e8d8bef9SDimitry Andric } 188*e8d8bef9SDimitry Andric 189*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) { 190*e8d8bef9SDimitry Andric ensureFuzzerInited(); 191*e8d8bef9SDimitry Andric int result = REAL(strcasecmp)(s1, s2); 192*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result); 193*e8d8bef9SDimitry Andric return result; 194*e8d8bef9SDimitry Andric } 195*e8d8bef9SDimitry Andric 196*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) { 197*e8d8bef9SDimitry Andric if (!FuzzerInited) 198*e8d8bef9SDimitry Andric return internal_strstr(s1, s2); 199*e8d8bef9SDimitry Andric char *result = REAL(strstr)(s1, s2); 200*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result); 201*e8d8bef9SDimitry Andric return result; 202*e8d8bef9SDimitry Andric } 203*e8d8bef9SDimitry Andric 204*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) { 205*e8d8bef9SDimitry Andric ensureFuzzerInited(); 206*e8d8bef9SDimitry Andric char *result = REAL(strcasestr)(s1, s2); 207*e8d8bef9SDimitry Andric __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result); 208*e8d8bef9SDimitry Andric return result; 209*e8d8bef9SDimitry Andric } 210*e8d8bef9SDimitry Andric 211*e8d8bef9SDimitry Andric ATTRIBUTE_INTERFACE 212*e8d8bef9SDimitry Andric void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) { 213*e8d8bef9SDimitry Andric ensureFuzzerInited(); 214*e8d8bef9SDimitry Andric void *result = REAL(memmem)(s1, len1, s2, len2); 215*e8d8bef9SDimitry Andric __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2, result); 216*e8d8bef9SDimitry Andric return result; 217*e8d8bef9SDimitry Andric } 218*e8d8bef9SDimitry Andric 219*e8d8bef9SDimitry Andric __attribute__((section(".preinit_array"), 220*e8d8bef9SDimitry Andric used)) static void (*__local_fuzzer_preinit)(void) = fuzzerInit; 221*e8d8bef9SDimitry Andric 222*e8d8bef9SDimitry Andric } // extern "C" 223*e8d8bef9SDimitry Andric 224*e8d8bef9SDimitry Andric static void fuzzerInit() { 225*e8d8bef9SDimitry Andric assert(!FuzzerInitIsRunning); 226*e8d8bef9SDimitry Andric if (FuzzerInited) 227*e8d8bef9SDimitry Andric return; 228*e8d8bef9SDimitry Andric FuzzerInitIsRunning = true; 229*e8d8bef9SDimitry Andric 230*e8d8bef9SDimitry Andric REAL(bcmp) = reinterpret_cast<memcmp_type>( 231*e8d8bef9SDimitry Andric getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp))); 232*e8d8bef9SDimitry Andric REAL(memcmp) = reinterpret_cast<memcmp_type>( 233*e8d8bef9SDimitry Andric getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp))); 234*e8d8bef9SDimitry Andric REAL(strncmp) = reinterpret_cast<strncmp_type>( 235*e8d8bef9SDimitry Andric getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp))); 236*e8d8bef9SDimitry Andric REAL(strcmp) = reinterpret_cast<strcmp_type>( 237*e8d8bef9SDimitry Andric getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp))); 238*e8d8bef9SDimitry Andric REAL(strncasecmp) = reinterpret_cast<strncasecmp_type>( 239*e8d8bef9SDimitry Andric getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp))); 240*e8d8bef9SDimitry Andric REAL(strcasecmp) = reinterpret_cast<strcasecmp_type>( 241*e8d8bef9SDimitry Andric getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp))); 242*e8d8bef9SDimitry Andric REAL(strstr) = reinterpret_cast<strstr_type>( 243*e8d8bef9SDimitry Andric getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr))); 244*e8d8bef9SDimitry Andric REAL(strcasestr) = reinterpret_cast<strcasestr_type>( 245*e8d8bef9SDimitry Andric getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr))); 246*e8d8bef9SDimitry Andric REAL(memmem) = reinterpret_cast<memmem_type>( 247*e8d8bef9SDimitry Andric getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem))); 248*e8d8bef9SDimitry Andric 249*e8d8bef9SDimitry Andric FuzzerInitIsRunning = false; 250*e8d8bef9SDimitry Andric FuzzerInited = 1; 251*e8d8bef9SDimitry Andric } 252*e8d8bef9SDimitry Andric 253*e8d8bef9SDimitry Andric #endif 254