xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/nsan/nsan_interceptors.cpp (revision 52418fc2be8efa5172b90a3a9e617017173612c4)
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