Path: blob/main/contrib/llvm-project/compiler-rt/lib/nsan/nsan_interceptors.cpp
35233 views
//===- nsan_interceptors.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Interceptors for standard library functions.9//10// A note about `printf`: Make sure none of the interceptor code calls any11// part of the nsan framework that can call `printf`, since this could create12// a loop (`printf` itself uses the libc). printf-free functions are documented13// as such in nsan.h.14//15//===----------------------------------------------------------------------===//1617#include "interception/interception.h"18#include "nsan/nsan.h"19#include "sanitizer_common/sanitizer_common.h"2021#include <wchar.h>2223using namespace __sanitizer;24using __nsan::nsan_init_is_running;25using __nsan::nsan_initialized;2627template <typename T> T min(T a, T b) { return a < b ? a : b; }2829INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {30// NOTE: This guard is needed because nsan's initialization code might call31// memset.32if (!nsan_initialized && REAL(memset) == nullptr)33return internal_memset(dst, v, size);3435void *res = REAL(memset)(dst, v, size);36__nsan_set_value_unknown(static_cast<u8 *>(dst), size);37return res;38}3940INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) {41wchar_t *res = REAL(wmemset)(dst, v, size);42__nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size);43return res;44}4546INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {47// NOTE: This guard is needed because nsan's initialization code might call48// memmove.49if (!nsan_initialized && REAL(memmove) == nullptr)50return internal_memmove(dst, src, size);5152void *res = REAL(memmove)(dst, src, size);53__nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),54size);55return res;56}5758INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, uptr size) {59wchar_t *res = REAL(wmemmove)(dst, src, size);60__nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);61return res;62}6364INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) {65// NOTE: This guard is needed because nsan's initialization code might call66// memcpy.67if (!nsan_initialized && REAL(memcpy) == nullptr) {68// memmove is used here because on some platforms this will also69// intercept the memmove implementation.70return internal_memmove(dst, src, size);71}7273void *res = REAL(memcpy)(dst, src, size);74__nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src),75size);76return res;77}7879INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) {80wchar_t *res = REAL(wmemcpy)(dst, src, size);81__nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size);82return res;83}8485INTERCEPTOR(char *, strfry, char *s) {86const auto Len = internal_strlen(s);87char *res = REAL(strfry)(s);88if (res)89__nsan_set_value_unknown(reinterpret_cast<u8 *>(s), Len);90return res;91}9293INTERCEPTOR(char *, strsep, char **Stringp, const char *delim) {94char *OrigStringp = REAL(strsep)(Stringp, delim);95if (Stringp != nullptr) {96// The previous character has been overwritten with a '\0' char.97__nsan_set_value_unknown(reinterpret_cast<u8 *>(*Stringp) - 1, 1);98}99return OrigStringp;100}101102INTERCEPTOR(char *, strtok, char *str, const char *delim) {103// This is overly conservative, but the probability that modern code is using104// strtok on double data is essentially zero anyway.105if (str)106__nsan_set_value_unknown(reinterpret_cast<u8 *>(str), internal_strlen(str));107return REAL(strtok)(str, delim);108}109110static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) {111__nsan_copy_values(reinterpret_cast<u8 *>(dst),112reinterpret_cast<const u8 *>(src), n); // Data.113__nsan_set_value_unknown(reinterpret_cast<u8 *>(dst) + n, 1); // Terminator.114}115116static void nsanWCopyZeroTerminated(wchar_t *dst, const wchar_t *src, uptr n) {117__nsan_copy_values((u8 *)dst, (const u8 *)(src), sizeof(wchar_t) * n);118__nsan_set_value_unknown((u8 *)(dst + n), sizeof(wchar_t));119}120121INTERCEPTOR(char *, strdup, const char *S) {122char *res = REAL(strdup)(S);123if (res) {124nsanCopyZeroTerminated(res, S, internal_strlen(S));125}126return res;127}128129INTERCEPTOR(wchar_t *, wcsdup, const wchar_t *S) {130wchar_t *res = REAL(wcsdup)(S);131if (res) {132nsanWCopyZeroTerminated(res, S, wcslen(S));133}134return res;135}136137INTERCEPTOR(char *, strndup, const char *S, uptr size) {138char *res = REAL(strndup)(S, size);139if (res) {140nsanCopyZeroTerminated(res, S, min(internal_strlen(S), size));141}142return res;143}144145INTERCEPTOR(char *, strcpy, char *dst, const char *src) {146char *res = REAL(strcpy)(dst, src);147nsanCopyZeroTerminated(dst, src, internal_strlen(src));148return res;149}150151INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) {152wchar_t *res = REAL(wcscpy)(dst, src);153nsanWCopyZeroTerminated(dst, src, wcslen(src));154return res;155}156157INTERCEPTOR(char *, strncpy, char *dst, const char *src, uptr size) {158char *res = REAL(strncpy)(dst, src, size);159nsanCopyZeroTerminated(dst, src, min(size, internal_strlen(src)));160return res;161}162163INTERCEPTOR(char *, strcat, char *dst, const char *src) {164const auto DstLenBeforeCat = internal_strlen(dst);165char *res = REAL(strcat)(dst, src);166nsanCopyZeroTerminated(dst + DstLenBeforeCat, src, internal_strlen(src));167return res;168}169170INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) {171const auto DstLenBeforeCat = wcslen(dst);172wchar_t *res = REAL(wcscat)(dst, src);173nsanWCopyZeroTerminated(dst + DstLenBeforeCat, src, wcslen(src));174return res;175}176177INTERCEPTOR(char *, strncat, char *dst, const char *src, uptr size) {178const auto DstLen = internal_strlen(dst);179char *res = REAL(strncat)(dst, src, size);180nsanCopyZeroTerminated(dst + DstLen, src, min(size, internal_strlen(src)));181return res;182}183184INTERCEPTOR(char *, stpcpy, char *dst, const char *src) {185char *res = REAL(stpcpy)(dst, src);186nsanCopyZeroTerminated(dst, src, internal_strlen(src));187return res;188}189190INTERCEPTOR(wchar_t *, wcpcpy, wchar_t *dst, const wchar_t *src) {191wchar_t *res = REAL(wcpcpy)(dst, src);192nsanWCopyZeroTerminated(dst, src, wcslen(src));193return res;194}195196INTERCEPTOR(uptr, strxfrm, char *dst, const char *src, uptr size) {197// This is overly conservative, but this function should very rarely be used.198__nsan_set_value_unknown(reinterpret_cast<u8 *>(dst), internal_strlen(dst));199const uptr res = REAL(strxfrm)(dst, src, size);200return res;201}202203void __nsan::InitializeInterceptors() {204static bool initialized = false;205CHECK(!initialized);206207InitializeMallocInterceptors();208209INTERCEPT_FUNCTION(memset);210INTERCEPT_FUNCTION(wmemset);211INTERCEPT_FUNCTION(memmove);212INTERCEPT_FUNCTION(wmemmove);213INTERCEPT_FUNCTION(memcpy);214INTERCEPT_FUNCTION(wmemcpy);215216INTERCEPT_FUNCTION(strdup);217INTERCEPT_FUNCTION(wcsdup);218INTERCEPT_FUNCTION(strndup);219INTERCEPT_FUNCTION(stpcpy);220INTERCEPT_FUNCTION(wcpcpy);221INTERCEPT_FUNCTION(strcpy);222INTERCEPT_FUNCTION(wcscpy);223INTERCEPT_FUNCTION(strncpy);224INTERCEPT_FUNCTION(strcat);225INTERCEPT_FUNCTION(wcscat);226INTERCEPT_FUNCTION(strncat);227INTERCEPT_FUNCTION(strxfrm);228229INTERCEPT_FUNCTION(strfry);230INTERCEPT_FUNCTION(strsep);231INTERCEPT_FUNCTION(strtok);232233initialized = 1;234}235236237