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