1*0fca6ea1SDimitry Andric //===- nsan_interceptors.cpp ----------------------------------------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // Interceptors for standard library functions. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric // A note about `printf`: Make sure none of the interceptor code calls any 12*0fca6ea1SDimitry Andric // part of the nsan framework that can call `printf`, since this could create 13*0fca6ea1SDimitry Andric // a loop (`printf` itself uses the libc). printf-free functions are documented 14*0fca6ea1SDimitry Andric // as such in nsan.h. 15*0fca6ea1SDimitry Andric // 16*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric #include "interception/interception.h" 19*0fca6ea1SDimitry Andric #include "nsan/nsan.h" 20*0fca6ea1SDimitry Andric #include "sanitizer_common/sanitizer_common.h" 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric #include <wchar.h> 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric using namespace __sanitizer; 25*0fca6ea1SDimitry Andric using __nsan::nsan_init_is_running; 26*0fca6ea1SDimitry Andric using __nsan::nsan_initialized; 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric template <typename T> T min(T a, T b) { return a < b ? a : b; } 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric INTERCEPTOR(void *, memset, void *dst, int v, uptr size) { 31*0fca6ea1SDimitry Andric // NOTE: This guard is needed because nsan's initialization code might call 32*0fca6ea1SDimitry Andric // memset. 33*0fca6ea1SDimitry Andric if (!nsan_initialized && REAL(memset) == nullptr) 34*0fca6ea1SDimitry Andric return internal_memset(dst, v, size); 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric void *res = REAL(memset)(dst, v, size); 37*0fca6ea1SDimitry Andric __nsan_set_value_unknown(static_cast<u8 *>(dst), size); 38*0fca6ea1SDimitry Andric return res; 39*0fca6ea1SDimitry Andric } 40*0fca6ea1SDimitry Andric 41*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wmemset, wchar_t *dst, wchar_t v, uptr size) { 42*0fca6ea1SDimitry Andric wchar_t *res = REAL(wmemset)(dst, v, size); 43*0fca6ea1SDimitry Andric __nsan_set_value_unknown((u8 *)dst, sizeof(wchar_t) * size); 44*0fca6ea1SDimitry Andric return res; 45*0fca6ea1SDimitry Andric } 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { 48*0fca6ea1SDimitry Andric // NOTE: This guard is needed because nsan's initialization code might call 49*0fca6ea1SDimitry Andric // memmove. 50*0fca6ea1SDimitry Andric if (!nsan_initialized && REAL(memmove) == nullptr) 51*0fca6ea1SDimitry Andric return internal_memmove(dst, src, size); 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric void *res = REAL(memmove)(dst, src, size); 54*0fca6ea1SDimitry Andric __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src), 55*0fca6ea1SDimitry Andric size); 56*0fca6ea1SDimitry Andric return res; 57*0fca6ea1SDimitry Andric } 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wmemmove, wchar_t *dst, const wchar_t *src, uptr size) { 60*0fca6ea1SDimitry Andric wchar_t *res = REAL(wmemmove)(dst, src, size); 61*0fca6ea1SDimitry Andric __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); 62*0fca6ea1SDimitry Andric return res; 63*0fca6ea1SDimitry Andric } 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { 66*0fca6ea1SDimitry Andric // NOTE: This guard is needed because nsan's initialization code might call 67*0fca6ea1SDimitry Andric // memcpy. 68*0fca6ea1SDimitry Andric if (!nsan_initialized && REAL(memcpy) == nullptr) { 69*0fca6ea1SDimitry Andric // memmove is used here because on some platforms this will also 70*0fca6ea1SDimitry Andric // intercept the memmove implementation. 71*0fca6ea1SDimitry Andric return internal_memmove(dst, src, size); 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric void *res = REAL(memcpy)(dst, src, size); 75*0fca6ea1SDimitry Andric __nsan_copy_values(static_cast<u8 *>(dst), static_cast<const u8 *>(src), 76*0fca6ea1SDimitry Andric size); 77*0fca6ea1SDimitry Andric return res; 78*0fca6ea1SDimitry Andric } 79*0fca6ea1SDimitry Andric 80*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wmemcpy, wchar_t *dst, const wchar_t *src, uptr size) { 81*0fca6ea1SDimitry Andric wchar_t *res = REAL(wmemcpy)(dst, src, size); 82*0fca6ea1SDimitry Andric __nsan_copy_values((u8 *)dst, (const u8 *)src, sizeof(wchar_t) * size); 83*0fca6ea1SDimitry Andric return res; 84*0fca6ea1SDimitry Andric } 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strfry, char *s) { 87*0fca6ea1SDimitry Andric const auto Len = internal_strlen(s); 88*0fca6ea1SDimitry Andric char *res = REAL(strfry)(s); 89*0fca6ea1SDimitry Andric if (res) 90*0fca6ea1SDimitry Andric __nsan_set_value_unknown(reinterpret_cast<u8 *>(s), Len); 91*0fca6ea1SDimitry Andric return res; 92*0fca6ea1SDimitry Andric } 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strsep, char **Stringp, const char *delim) { 95*0fca6ea1SDimitry Andric char *OrigStringp = REAL(strsep)(Stringp, delim); 96*0fca6ea1SDimitry Andric if (Stringp != nullptr) { 97*0fca6ea1SDimitry Andric // The previous character has been overwritten with a '\0' char. 98*0fca6ea1SDimitry Andric __nsan_set_value_unknown(reinterpret_cast<u8 *>(*Stringp) - 1, 1); 99*0fca6ea1SDimitry Andric } 100*0fca6ea1SDimitry Andric return OrigStringp; 101*0fca6ea1SDimitry Andric } 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strtok, char *str, const char *delim) { 104*0fca6ea1SDimitry Andric // This is overly conservative, but the probability that modern code is using 105*0fca6ea1SDimitry Andric // strtok on double data is essentially zero anyway. 106*0fca6ea1SDimitry Andric if (str) 107*0fca6ea1SDimitry Andric __nsan_set_value_unknown(reinterpret_cast<u8 *>(str), internal_strlen(str)); 108*0fca6ea1SDimitry Andric return REAL(strtok)(str, delim); 109*0fca6ea1SDimitry Andric } 110*0fca6ea1SDimitry Andric 111*0fca6ea1SDimitry Andric static void nsanCopyZeroTerminated(char *dst, const char *src, uptr n) { 112*0fca6ea1SDimitry Andric __nsan_copy_values(reinterpret_cast<u8 *>(dst), 113*0fca6ea1SDimitry Andric reinterpret_cast<const u8 *>(src), n); // Data. 114*0fca6ea1SDimitry Andric __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst) + n, 1); // Terminator. 115*0fca6ea1SDimitry Andric } 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric static void nsanWCopyZeroTerminated(wchar_t *dst, const wchar_t *src, uptr n) { 118*0fca6ea1SDimitry Andric __nsan_copy_values((u8 *)dst, (const u8 *)(src), sizeof(wchar_t) * n); 119*0fca6ea1SDimitry Andric __nsan_set_value_unknown((u8 *)(dst + n), sizeof(wchar_t)); 120*0fca6ea1SDimitry Andric } 121*0fca6ea1SDimitry Andric 122*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strdup, const char *S) { 123*0fca6ea1SDimitry Andric char *res = REAL(strdup)(S); 124*0fca6ea1SDimitry Andric if (res) { 125*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(res, S, internal_strlen(S)); 126*0fca6ea1SDimitry Andric } 127*0fca6ea1SDimitry Andric return res; 128*0fca6ea1SDimitry Andric } 129*0fca6ea1SDimitry Andric 130*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wcsdup, const wchar_t *S) { 131*0fca6ea1SDimitry Andric wchar_t *res = REAL(wcsdup)(S); 132*0fca6ea1SDimitry Andric if (res) { 133*0fca6ea1SDimitry Andric nsanWCopyZeroTerminated(res, S, wcslen(S)); 134*0fca6ea1SDimitry Andric } 135*0fca6ea1SDimitry Andric return res; 136*0fca6ea1SDimitry Andric } 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strndup, const char *S, uptr size) { 139*0fca6ea1SDimitry Andric char *res = REAL(strndup)(S, size); 140*0fca6ea1SDimitry Andric if (res) { 141*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(res, S, min(internal_strlen(S), size)); 142*0fca6ea1SDimitry Andric } 143*0fca6ea1SDimitry Andric return res; 144*0fca6ea1SDimitry Andric } 145*0fca6ea1SDimitry Andric 146*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strcpy, char *dst, const char *src) { 147*0fca6ea1SDimitry Andric char *res = REAL(strcpy)(dst, src); 148*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(dst, src, internal_strlen(src)); 149*0fca6ea1SDimitry Andric return res; 150*0fca6ea1SDimitry Andric } 151*0fca6ea1SDimitry Andric 152*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wcscpy, wchar_t *dst, const wchar_t *src) { 153*0fca6ea1SDimitry Andric wchar_t *res = REAL(wcscpy)(dst, src); 154*0fca6ea1SDimitry Andric nsanWCopyZeroTerminated(dst, src, wcslen(src)); 155*0fca6ea1SDimitry Andric return res; 156*0fca6ea1SDimitry Andric } 157*0fca6ea1SDimitry Andric 158*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strncpy, char *dst, const char *src, uptr size) { 159*0fca6ea1SDimitry Andric char *res = REAL(strncpy)(dst, src, size); 160*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(dst, src, min(size, internal_strlen(src))); 161*0fca6ea1SDimitry Andric return res; 162*0fca6ea1SDimitry Andric } 163*0fca6ea1SDimitry Andric 164*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strcat, char *dst, const char *src) { 165*0fca6ea1SDimitry Andric const auto DstLenBeforeCat = internal_strlen(dst); 166*0fca6ea1SDimitry Andric char *res = REAL(strcat)(dst, src); 167*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(dst + DstLenBeforeCat, src, internal_strlen(src)); 168*0fca6ea1SDimitry Andric return res; 169*0fca6ea1SDimitry Andric } 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) { 172*0fca6ea1SDimitry Andric const auto DstLenBeforeCat = wcslen(dst); 173*0fca6ea1SDimitry Andric wchar_t *res = REAL(wcscat)(dst, src); 174*0fca6ea1SDimitry Andric nsanWCopyZeroTerminated(dst + DstLenBeforeCat, src, wcslen(src)); 175*0fca6ea1SDimitry Andric return res; 176*0fca6ea1SDimitry Andric } 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric INTERCEPTOR(char *, strncat, char *dst, const char *src, uptr size) { 179*0fca6ea1SDimitry Andric const auto DstLen = internal_strlen(dst); 180*0fca6ea1SDimitry Andric char *res = REAL(strncat)(dst, src, size); 181*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(dst + DstLen, src, min(size, internal_strlen(src))); 182*0fca6ea1SDimitry Andric return res; 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric INTERCEPTOR(char *, stpcpy, char *dst, const char *src) { 186*0fca6ea1SDimitry Andric char *res = REAL(stpcpy)(dst, src); 187*0fca6ea1SDimitry Andric nsanCopyZeroTerminated(dst, src, internal_strlen(src)); 188*0fca6ea1SDimitry Andric return res; 189*0fca6ea1SDimitry Andric } 190*0fca6ea1SDimitry Andric 191*0fca6ea1SDimitry Andric INTERCEPTOR(wchar_t *, wcpcpy, wchar_t *dst, const wchar_t *src) { 192*0fca6ea1SDimitry Andric wchar_t *res = REAL(wcpcpy)(dst, src); 193*0fca6ea1SDimitry Andric nsanWCopyZeroTerminated(dst, src, wcslen(src)); 194*0fca6ea1SDimitry Andric return res; 195*0fca6ea1SDimitry Andric } 196*0fca6ea1SDimitry Andric 197*0fca6ea1SDimitry Andric INTERCEPTOR(uptr, strxfrm, char *dst, const char *src, uptr size) { 198*0fca6ea1SDimitry Andric // This is overly conservative, but this function should very rarely be used. 199*0fca6ea1SDimitry Andric __nsan_set_value_unknown(reinterpret_cast<u8 *>(dst), internal_strlen(dst)); 200*0fca6ea1SDimitry Andric const uptr res = REAL(strxfrm)(dst, src, size); 201*0fca6ea1SDimitry Andric return res; 202*0fca6ea1SDimitry Andric } 203*0fca6ea1SDimitry Andric 204*0fca6ea1SDimitry Andric void __nsan::InitializeInterceptors() { 205*0fca6ea1SDimitry Andric static bool initialized = false; 206*0fca6ea1SDimitry Andric CHECK(!initialized); 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric InitializeMallocInterceptors(); 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(memset); 211*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wmemset); 212*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(memmove); 213*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wmemmove); 214*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(memcpy); 215*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wmemcpy); 216*0fca6ea1SDimitry Andric 217*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strdup); 218*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wcsdup); 219*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strndup); 220*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(stpcpy); 221*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wcpcpy); 222*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strcpy); 223*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wcscpy); 224*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strncpy); 225*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strcat); 226*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(wcscat); 227*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strncat); 228*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strxfrm); 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strfry); 231*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strsep); 232*0fca6ea1SDimitry Andric INTERCEPT_FUNCTION(strtok); 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric initialized = 1; 235*0fca6ea1SDimitry Andric } 236