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); \
29 #include <dlfcn.h> // for dlsym()
31 static void *getFuncAddr(const char *name
, uintptr_t wrapper_addr
) {
32 void *addr
= dlsym(RTLD_NEXT
, name
);
34 // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
35 // later in the library search order than the DSO that we are trying to
36 // intercept, which means that we cannot intercept this function. We still
37 // want the address of the real definition, though, so look it up using
39 addr
= dlsym(RTLD_DEFAULT
, name
);
41 // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
42 // We don't want to intercept the wrapper and have it point to itself.
43 if (reinterpret_cast<uintptr_t>(addr
) == wrapper_addr
)
49 static int FuzzerInited
= 0;
50 static bool FuzzerInitIsRunning
;
52 static void fuzzerInit();
54 static void ensureFuzzerInited() {
55 assert(!FuzzerInitIsRunning
);
61 static int internal_strcmp_strncmp(const char *s1
, const char *s2
, bool strncmp
,
73 return (c1
< c2
) ? -1 : 1;
82 static int internal_strncmp(const char *s1
, const char *s2
, size_t n
) {
83 return internal_strcmp_strncmp(s1
, s2
, true, n
);
86 static int internal_strcmp(const char *s1
, const char *s2
) {
87 return internal_strcmp_strncmp(s1
, s2
, false, 0);
90 static int internal_memcmp(const void *s1
, const void *s2
, size_t n
) {
91 const uint8_t *t1
= static_cast<const uint8_t *>(s1
);
92 const uint8_t *t2
= static_cast<const uint8_t *>(s2
);
93 for (size_t i
= 0; i
< n
; ++i
, ++t1
, ++t2
)
95 return *t1
< *t2
? -1 : 1;
99 static size_t internal_strlen(const char *s
) {
106 static char *internal_strstr(const char *haystack
, const char *needle
) {
107 // This is O(N^2), but we are not using it in hot places.
108 size_t len1
= internal_strlen(haystack
);
109 size_t len2
= internal_strlen(needle
);
112 for (size_t pos
= 0; pos
<= len1
- len2
; pos
++) {
113 if (internal_memcmp(haystack
+ pos
, needle
, len2
) == 0)
114 return const_cast<char *>(haystack
) + pos
;
121 // Weak hooks forward-declared to avoid dependency on
122 // <sanitizer/common_interface_defs.h>.
123 void __sanitizer_weak_hook_memcmp(void *called_pc
, const void *s1
,
124 const void *s2
, size_t n
, int result
);
125 void __sanitizer_weak_hook_strncmp(void *called_pc
, const char *s1
,
126 const char *s2
, size_t n
, int result
);
127 void __sanitizer_weak_hook_strncasecmp(void *called_pc
, const char *s1
,
128 const char *s2
, size_t n
, int result
);
129 void __sanitizer_weak_hook_strcmp(void *called_pc
, const char *s1
,
130 const char *s2
, int result
);
131 void __sanitizer_weak_hook_strcasecmp(void *called_pc
, const char *s1
,
132 const char *s2
, int result
);
133 void __sanitizer_weak_hook_strstr(void *called_pc
, const char *s1
,
134 const char *s2
, char *result
);
135 void __sanitizer_weak_hook_strcasestr(void *called_pc
, const char *s1
,
136 const char *s2
, char *result
);
137 void __sanitizer_weak_hook_memmem(void *called_pc
, const void *s1
, size_t len1
,
138 const void *s2
, size_t len2
, void *result
);
140 DEFINE_REAL(int, bcmp
, const void *, const void *, size_t)
141 DEFINE_REAL(int, memcmp
, const void *, const void *, size_t)
142 DEFINE_REAL(int, strncmp
, const char *, const char *, size_t)
143 DEFINE_REAL(int, strcmp
, const char *, const char *)
144 DEFINE_REAL(int, strncasecmp
, const char *, const char *, size_t)
145 DEFINE_REAL(int, strcasecmp
, const char *, const char *)
146 DEFINE_REAL(char *, strstr
, const char *, const char *)
147 DEFINE_REAL(char *, strcasestr
, const char *, const char *)
148 DEFINE_REAL(void *, memmem
, const void *, size_t, const void *, size_t)
150 ATTRIBUTE_INTERFACE
int bcmp(const char *s1
, const char *s2
, size_t n
) {
152 return internal_memcmp(s1
, s2
, n
);
153 int result
= REAL(bcmp
)(s1
, s2
, n
);
154 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
158 ATTRIBUTE_INTERFACE
int memcmp(const void *s1
, const void *s2
, size_t n
) {
160 return internal_memcmp(s1
, s2
, n
);
161 int result
= REAL(memcmp
)(s1
, s2
, n
);
162 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
166 ATTRIBUTE_INTERFACE
int strncmp(const char *s1
, const char *s2
, size_t n
) {
168 return internal_strncmp(s1
, s2
, n
);
169 int result
= REAL(strncmp
)(s1
, s2
, n
);
170 __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
174 ATTRIBUTE_INTERFACE
int strcmp(const char *s1
, const char *s2
) {
176 return internal_strcmp(s1
, s2
);
177 int result
= REAL(strcmp
)(s1
, s2
);
178 __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1
, s2
, result
);
182 ATTRIBUTE_INTERFACE
int strncasecmp(const char *s1
, const char *s2
, size_t n
) {
183 ensureFuzzerInited();
184 int result
= REAL(strncasecmp
)(s1
, s2
, n
);
185 __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
189 ATTRIBUTE_INTERFACE
int strcasecmp(const char *s1
, const char *s2
) {
190 ensureFuzzerInited();
191 int result
= REAL(strcasecmp
)(s1
, s2
);
192 __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1
, s2
, result
);
196 ATTRIBUTE_INTERFACE
char *strstr(const char *s1
, const char *s2
) {
198 return internal_strstr(s1
, s2
);
199 char *result
= REAL(strstr
)(s1
, s2
);
200 __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1
, s2
, result
);
204 ATTRIBUTE_INTERFACE
char *strcasestr(const char *s1
, const char *s2
) {
205 ensureFuzzerInited();
206 char *result
= REAL(strcasestr
)(s1
, s2
);
207 __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1
, s2
, result
);
212 void *memmem(const void *s1
, size_t len1
, const void *s2
, size_t len2
) {
213 ensureFuzzerInited();
214 void *result
= REAL(memmem
)(s1
, len1
, s2
, len2
);
215 __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1
, len1
, s2
, len2
, result
);
219 __attribute__((section(".preinit_array"),
220 used
)) static void (*__local_fuzzer_preinit
)(void) = fuzzerInit
;
224 static void fuzzerInit() {
225 assert(!FuzzerInitIsRunning
);
228 FuzzerInitIsRunning
= true;
230 REAL(bcmp
) = reinterpret_cast<memcmp_type
>(
231 getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp
)));
232 REAL(memcmp
) = reinterpret_cast<memcmp_type
>(
233 getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp
)));
234 REAL(strncmp
) = reinterpret_cast<strncmp_type
>(
235 getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp
)));
236 REAL(strcmp
) = reinterpret_cast<strcmp_type
>(
237 getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp
)));
238 REAL(strncasecmp
) = reinterpret_cast<strncasecmp_type
>(
239 getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp
)));
240 REAL(strcasecmp
) = reinterpret_cast<strcasecmp_type
>(
241 getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp
)));
242 REAL(strstr
) = reinterpret_cast<strstr_type
>(
243 getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr
)));
244 REAL(strcasestr
) = reinterpret_cast<strcasestr_type
>(
245 getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr
)));
246 REAL(memmem
) = reinterpret_cast<memmem_type
>(
247 getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem
)));
249 FuzzerInitIsRunning
= false;