1 //===-- FuzzerInterceptors.cpp --------------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
8 // Intercept certain libc functions to aid fuzzing.
9 // Linked only when other RTs that define their own interceptors are not linked.
10 //===----------------------------------------------------------------------===//
12 #include "FuzzerPlatform.h"
16 #define GET_CALLER_PC() __builtin_return_address(0)
18 #define PTR_TO_REAL(x) real_##x
19 #define REAL(x) __interception::PTR_TO_REAL(x)
20 #define FUNC_TYPE(x) x##_type
21 #define DEFINE_REAL(ret_type, func, ...) \
22 typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
23 namespace __interception { \
24 FUNC_TYPE(func) PTR_TO_REAL(func); \
28 #include <cstddef> // for size_t
30 #include <dlfcn.h> // for dlsym()
32 static void *getFuncAddr(const char *name
, uintptr_t wrapper_addr
) {
33 void *addr
= dlsym(RTLD_NEXT
, name
);
35 // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
36 // later in the library search order than the DSO that we are trying to
37 // intercept, which means that we cannot intercept this function. We still
38 // want the address of the real definition, though, so look it up using
40 addr
= dlsym(RTLD_DEFAULT
, name
);
42 // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
43 // We don't want to intercept the wrapper and have it point to itself.
44 if (reinterpret_cast<uintptr_t>(addr
) == wrapper_addr
)
50 static int FuzzerInited
= 0;
51 static bool FuzzerInitIsRunning
;
53 static void fuzzerInit();
55 static void ensureFuzzerInited() {
56 assert(!FuzzerInitIsRunning
);
62 static int internal_strcmp_strncmp(const char *s1
, const char *s2
, bool strncmp
,
74 return (c1
< c2
) ? -1 : 1;
83 static int internal_strncmp(const char *s1
, const char *s2
, size_t n
) {
84 return internal_strcmp_strncmp(s1
, s2
, true, n
);
87 static int internal_strcmp(const char *s1
, const char *s2
) {
88 return internal_strcmp_strncmp(s1
, s2
, false, 0);
91 static int internal_memcmp(const void *s1
, const void *s2
, size_t n
) {
92 const uint8_t *t1
= static_cast<const uint8_t *>(s1
);
93 const uint8_t *t2
= static_cast<const uint8_t *>(s2
);
94 for (size_t i
= 0; i
< n
; ++i
, ++t1
, ++t2
)
96 return *t1
< *t2
? -1 : 1;
100 static size_t internal_strlen(const char *s
) {
107 static char *internal_strstr(const char *haystack
, const char *needle
) {
108 // This is O(N^2), but we are not using it in hot places.
109 size_t len1
= internal_strlen(haystack
);
110 size_t len2
= internal_strlen(needle
);
113 for (size_t pos
= 0; pos
<= len1
- len2
; pos
++) {
114 if (internal_memcmp(haystack
+ pos
, needle
, len2
) == 0)
115 return const_cast<char *>(haystack
) + pos
;
122 // Weak hooks forward-declared to avoid dependency on
123 // <sanitizer/common_interface_defs.h>.
124 void __sanitizer_weak_hook_memcmp(void *called_pc
, const void *s1
,
125 const void *s2
, size_t n
, int result
);
126 void __sanitizer_weak_hook_strncmp(void *called_pc
, const char *s1
,
127 const char *s2
, size_t n
, int result
);
128 void __sanitizer_weak_hook_strncasecmp(void *called_pc
, const char *s1
,
129 const char *s2
, size_t n
, int result
);
130 void __sanitizer_weak_hook_strcmp(void *called_pc
, const char *s1
,
131 const char *s2
, int result
);
132 void __sanitizer_weak_hook_strcasecmp(void *called_pc
, const char *s1
,
133 const char *s2
, int result
);
134 void __sanitizer_weak_hook_strstr(void *called_pc
, const char *s1
,
135 const char *s2
, char *result
);
136 void __sanitizer_weak_hook_strcasestr(void *called_pc
, const char *s1
,
137 const char *s2
, char *result
);
138 void __sanitizer_weak_hook_memmem(void *called_pc
, const void *s1
, size_t len1
,
139 const void *s2
, size_t len2
, void *result
);
141 DEFINE_REAL(int, bcmp
, const void *, const void *, size_t)
142 DEFINE_REAL(int, memcmp
, const void *, const void *, size_t)
143 DEFINE_REAL(int, strncmp
, const char *, const char *, size_t)
144 DEFINE_REAL(int, strcmp
, const char *, const char *)
145 DEFINE_REAL(int, strncasecmp
, const char *, const char *, size_t)
146 DEFINE_REAL(int, strcasecmp
, const char *, const char *)
147 DEFINE_REAL(char *, strstr
, const char *, const char *)
148 DEFINE_REAL(char *, strcasestr
, const char *, const char *)
149 DEFINE_REAL(void *, memmem
, const void *, size_t, const void *, size_t)
151 ATTRIBUTE_INTERFACE
int bcmp(const char *s1
, const char *s2
, size_t n
) {
153 return internal_memcmp(s1
, s2
, n
);
154 int result
= REAL(bcmp
)(s1
, s2
, n
);
155 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
159 ATTRIBUTE_INTERFACE
int memcmp(const void *s1
, const void *s2
, size_t n
) {
161 return internal_memcmp(s1
, s2
, n
);
162 int result
= REAL(memcmp
)(s1
, s2
, n
);
163 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
167 ATTRIBUTE_INTERFACE
int strncmp(const char *s1
, const char *s2
, size_t n
) {
169 return internal_strncmp(s1
, s2
, n
);
170 int result
= REAL(strncmp
)(s1
, s2
, n
);
171 __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
175 ATTRIBUTE_INTERFACE
int strcmp(const char *s1
, const char *s2
) {
177 return internal_strcmp(s1
, s2
);
178 int result
= REAL(strcmp
)(s1
, s2
);
179 __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1
, s2
, result
);
183 ATTRIBUTE_INTERFACE
int strncasecmp(const char *s1
, const char *s2
, size_t n
) {
184 ensureFuzzerInited();
185 int result
= REAL(strncasecmp
)(s1
, s2
, n
);
186 __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
190 ATTRIBUTE_INTERFACE
int strcasecmp(const char *s1
, const char *s2
) {
191 ensureFuzzerInited();
192 int result
= REAL(strcasecmp
)(s1
, s2
);
193 __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1
, s2
, result
);
197 ATTRIBUTE_INTERFACE
char *strstr(const char *s1
, const char *s2
) {
199 return internal_strstr(s1
, s2
);
200 char *result
= REAL(strstr
)(s1
, s2
);
201 __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1
, s2
, result
);
205 ATTRIBUTE_INTERFACE
char *strcasestr(const char *s1
, const char *s2
) {
206 ensureFuzzerInited();
207 char *result
= REAL(strcasestr
)(s1
, s2
);
208 __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1
, s2
, result
);
213 void *memmem(const void *s1
, size_t len1
, const void *s2
, size_t len2
) {
214 ensureFuzzerInited();
215 void *result
= REAL(memmem
)(s1
, len1
, s2
, len2
);
216 __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1
, len1
, s2
, len2
, result
);
220 __attribute__((section(".preinit_array"),
221 used
)) static void (*__local_fuzzer_preinit
)(void) = fuzzerInit
;
225 static void fuzzerInit() {
226 assert(!FuzzerInitIsRunning
);
229 FuzzerInitIsRunning
= true;
231 REAL(bcmp
) = reinterpret_cast<memcmp_type
>(
232 getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp
)));
233 REAL(memcmp
) = reinterpret_cast<memcmp_type
>(
234 getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp
)));
235 REAL(strncmp
) = reinterpret_cast<strncmp_type
>(
236 getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp
)));
237 REAL(strcmp
) = reinterpret_cast<strcmp_type
>(
238 getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp
)));
239 REAL(strncasecmp
) = reinterpret_cast<strncasecmp_type
>(
240 getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp
)));
241 REAL(strcasecmp
) = reinterpret_cast<strcasecmp_type
>(
242 getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp
)));
243 REAL(strstr
) = reinterpret_cast<strstr_type
>(
244 getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr
)));
245 REAL(strcasestr
) = reinterpret_cast<strcasestr_type
>(
246 getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr
)));
247 REAL(memmem
) = reinterpret_cast<memmem_type
>(
248 getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem
)));
250 FuzzerInitIsRunning
= false;