brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.3 KiB · 2549f49 Raw
268 lines · cpp
1//===- nsan_interceptors.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//9// Interceptors for standard library functions.10//11// A note about `printf`: Make sure none of the interceptor code calls any12// part of the nsan framework that can call `printf`, since this could create13// a loop (`printf` itself uses the libc). printf-free functions are documented14// as such in nsan.h.15//16//===----------------------------------------------------------------------===//17 18#include "interception/interception.h"19#include "nsan.h"20#include "nsan_thread.h"21#include "sanitizer_common/sanitizer_common.h"22#include "sanitizer_common/sanitizer_linux.h"23 24#include <wchar.h>25 26using namespace __nsan;27using namespace __sanitizer;28 29template <typename T> T min(T a, T b) { return a < b ? a : b; }30 31INTERCEPTOR(void *, memset, void *dst, int v, usize size) {32  // NOTE: This guard is needed because nsan's initialization code might call33  // memset.34  if (!nsan_initialized && REAL(memset) == nullptr)35    return internal_memset(dst, v, size);36 37  void *res = REAL(memset)(dst, v, size);38  __nsan_set_value_unknown(static_cast<u8 *>(dst), size);39  return res;40}41 42INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, usize size) {43  wchar_t *res = REAL(wmemset)(dst, v, size);44  __nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size);45  return res;46}47 48INTERCEPTOR(void *, memmove, void *dst, const void *src, usize size) {49  // NOTE: This guard is needed because nsan's initialization code might call50  // memmove.51  if (!nsan_initialized && REAL(memmove) == nullptr)52    return internal_memmove(dst, src, size);53 54  void *res = REAL(memmove)(dst, src, size);55  __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),56                     size);57  return res;58}59 60INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, usize size) {61  wchar_t *res = REAL(wmemmove)(dst, src, size);62  __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);63  return res;64}65 66INTERCEPTOR(void *, memcpy, void *dst, const void *src, usize size) {67  // NOTE: This guard is needed because nsan's initialization code might call68  // memcpy.69  if (!nsan_initialized && REAL(memcpy) == nullptr) {70    // memmove is used here because on some platforms this will also71    // intercept the memmove implementation.72    return internal_memmove(dst, src, size);73  }74 75  void *res = REAL(memcpy)(dst, src, size);76  __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),77                     size);78  return res;79}80 81INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, usize size) {82  wchar_t *res = REAL(wmemcpy)(dst, src, size);83  __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);84  return res;85}86 87INTERCEPTOR(char *, strfry, char *s) {88  const auto Len = internal_strlen(s);89  char *res = REAL(strfry)(s);90  if (res)91    __nsan_set_value_unknown(reinterpret_cast<u8 *>(s), Len);92  return res;93}94 95INTERCEPTOR(char *, strsep, char **Stringp, const char *delim) {96  char *OrigStringp = REAL(strsep)(Stringp, delim);97  if (*Stringp != nullptr) {98    // The previous character has been overwritten with a '\0' char.99    __nsan_set_value_unknown(reinterpret_cast<u8 *>(*Stringp) - 1, 1);100  }101  return OrigStringp;102}103 104INTERCEPTOR(char *, strtok, char *str, const char *delim) {105  // This is overly conservative, but the probability that modern code is using106  // strtok on double data is essentially zero anyway.107  if (str)108    __nsan_set_value_unknown(reinterpret_cast<u8 *>(str), internal_strlen(str));109  return REAL(strtok)(str, delim);110}111 112static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) {113  __nsan_copy_values(reinterpret_cast<u8 *>(dst),114                     reinterpret_cast<const u8 *>(src), n);     // Data.115  __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst) + n, 1); // Terminator.116}117 118static void nsanWCopyZeroTerminated(wchar_t *dst, const wchar_t *src, uptr n) {119  __nsan_copy_values((u8 *)dst, (const u8 *)(src), sizeof(wchar_t) * n);120  __nsan_set_value_unknown((u8 *)(dst + n), sizeof(wchar_t));121}122 123INTERCEPTOR(char *, strdup, const char *S) {124  char *res = REAL(strdup)(S);125  if (res) {126    nsanCopyZeroTerminated(res, S, internal_strlen(S));127  }128  return res;129}130 131INTERCEPTOR(wchar_t *, wcsdup, const wchar_t *S) {132  wchar_t *res = REAL(wcsdup)(S);133  if (res) {134    nsanWCopyZeroTerminated(res, S, wcslen(S));135  }136  return res;137}138 139INTERCEPTOR(char *, strndup, const char *S, usize size) {140  char *res = REAL(strndup)(S, size);141  if (res) {142    nsanCopyZeroTerminated(res, S, min(internal_strlen(S), size));143  }144  return res;145}146 147INTERCEPTOR(char *, strcpy, char *dst, const char *src) {148  char *res = REAL(strcpy)(dst, src);149  nsanCopyZeroTerminated(dst, src, internal_strlen(src));150  return res;151}152 153INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) {154  wchar_t *res = REAL(wcscpy)(dst, src);155  nsanWCopyZeroTerminated(dst, src, wcslen(src));156  return res;157}158 159INTERCEPTOR(char *, strncpy, char *dst, const char *src, usize size) {160  char *res = REAL(strncpy)(dst, src, size);161  nsanCopyZeroTerminated(dst, src, min(size, internal_strlen(src)));162  return res;163}164 165INTERCEPTOR(char *, strcat, char *dst, const char *src) {166  const auto DstLenBeforeCat = internal_strlen(dst);167  char *res = REAL(strcat)(dst, src);168  nsanCopyZeroTerminated(dst + DstLenBeforeCat, src, internal_strlen(src));169  return res;170}171 172INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) {173  const auto DstLenBeforeCat = wcslen(dst);174  wchar_t *res = REAL(wcscat)(dst, src);175  nsanWCopyZeroTerminated(dst + DstLenBeforeCat, src, wcslen(src));176  return res;177}178 179INTERCEPTOR(char *, strncat, char *dst, const char *src, usize size) {180  const auto DstLen = internal_strlen(dst);181  char *res = REAL(strncat)(dst, src, size);182  nsanCopyZeroTerminated(dst + DstLen, src, min(size, internal_strlen(src)));183  return res;184}185 186INTERCEPTOR(char *, stpcpy, char *dst, const char *src) {187  char *res = REAL(stpcpy)(dst, src);188  nsanCopyZeroTerminated(dst, src, internal_strlen(src));189  return res;190}191 192INTERCEPTOR(wchar_t *, wcpcpy, wchar_t *dst, const wchar_t *src) {193  wchar_t *res = REAL(wcpcpy)(dst, src);194  nsanWCopyZeroTerminated(dst, src, wcslen(src));195  return res;196}197 198INTERCEPTOR(usize, strxfrm, char *dst, const char *src, usize size) {199  // This is overly conservative, but this function should very rarely be used.200  __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst), internal_strlen(dst));201  return REAL(strxfrm)(dst, src, size);202}203 204extern "C" int pthread_attr_init(void *attr);205extern "C" int pthread_attr_destroy(void *attr);206 207static void *NsanThreadStartFunc(void *arg) {208  auto *t = reinterpret_cast<NsanThread *>(arg);209  SetCurrentThread(t);210  t->Init();211  SetSigProcMask(&t->starting_sigset_, nullptr);212  return t->ThreadStart();213}214 215INTERCEPTOR(int, pthread_create, void *th, void *attr,216            void *(*callback)(void *), void *param) {217  __sanitizer_pthread_attr_t myattr;218  if (!attr) {219    pthread_attr_init(&myattr);220    attr = &myattr;221  }222 223  AdjustStackSize(attr);224 225  NsanThread *t = NsanThread::Create(callback, param);226  ScopedBlockSignals block(&t->starting_sigset_);227  int res = REAL(pthread_create)(th, attr, NsanThreadStartFunc, t);228 229  if (attr == &myattr)230    pthread_attr_destroy(&myattr);231  return res;232}233 234void __nsan::InitializeInterceptors() {235  static bool initialized = false;236  CHECK(!initialized);237 238  InitializeMallocInterceptors();239 240  INTERCEPT_FUNCTION(memset);241  INTERCEPT_FUNCTION(wmemset);242  INTERCEPT_FUNCTION(memmove);243  INTERCEPT_FUNCTION(wmemmove);244  INTERCEPT_FUNCTION(memcpy);245  INTERCEPT_FUNCTION(wmemcpy);246 247  INTERCEPT_FUNCTION(strdup);248  INTERCEPT_FUNCTION(wcsdup);249  INTERCEPT_FUNCTION(strndup);250  INTERCEPT_FUNCTION(stpcpy);251  INTERCEPT_FUNCTION(wcpcpy);252  INTERCEPT_FUNCTION(strcpy);253  INTERCEPT_FUNCTION(wcscpy);254  INTERCEPT_FUNCTION(strncpy);255  INTERCEPT_FUNCTION(strcat);256  INTERCEPT_FUNCTION(wcscat);257  INTERCEPT_FUNCTION(strncat);258  INTERCEPT_FUNCTION(strxfrm);259 260  INTERCEPT_FUNCTION(strfry);261  INTERCEPT_FUNCTION(strsep);262  INTERCEPT_FUNCTION(strtok);263 264  INTERCEPT_FUNCTION(pthread_create);265 266  initialized = 1;267}268