brintos

brintos / llvm-project-archived public Read only

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