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()
30 #include <sanitizer/common_interface_defs.h>
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 DEFINE_REAL(int, bcmp
, const void *, const void *, size_t)
123 DEFINE_REAL(int, memcmp
, const void *, const void *, size_t)
124 DEFINE_REAL(int, strncmp
, const char *, const char *, size_t)
125 DEFINE_REAL(int, strcmp
, const char *, const char *)
126 DEFINE_REAL(int, strncasecmp
, const char *, const char *, size_t)
127 DEFINE_REAL(int, strcasecmp
, const char *, const char *)
128 DEFINE_REAL(char *, strstr
, const char *, const char *)
129 DEFINE_REAL(char *, strcasestr
, const char *, const char *)
130 DEFINE_REAL(void *, memmem
, const void *, size_t, const void *, size_t)
132 ATTRIBUTE_INTERFACE
int bcmp(const char *s1
, const char *s2
, size_t n
) {
134 return internal_memcmp(s1
, s2
, n
);
135 int result
= REAL(bcmp
)(s1
, s2
, n
);
136 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
140 ATTRIBUTE_INTERFACE
int memcmp(const void *s1
, const void *s2
, size_t n
) {
142 return internal_memcmp(s1
, s2
, n
);
143 int result
= REAL(memcmp
)(s1
, s2
, n
);
144 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
148 ATTRIBUTE_INTERFACE
int strncmp(const char *s1
, const char *s2
, size_t n
) {
150 return internal_strncmp(s1
, s2
, n
);
151 int result
= REAL(strncmp
)(s1
, s2
, n
);
152 __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
156 ATTRIBUTE_INTERFACE
int strcmp(const char *s1
, const char *s2
) {
158 return internal_strcmp(s1
, s2
);
159 int result
= REAL(strcmp
)(s1
, s2
);
160 __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1
, s2
, result
);
164 ATTRIBUTE_INTERFACE
int strncasecmp(const char *s1
, const char *s2
, size_t n
) {
165 ensureFuzzerInited();
166 int result
= REAL(strncasecmp
)(s1
, s2
, n
);
167 __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1
, s2
, n
, result
);
171 ATTRIBUTE_INTERFACE
int strcasecmp(const char *s1
, const char *s2
) {
172 ensureFuzzerInited();
173 int result
= REAL(strcasecmp
)(s1
, s2
);
174 __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1
, s2
, result
);
178 ATTRIBUTE_INTERFACE
char *strstr(const char *s1
, const char *s2
) {
180 return internal_strstr(s1
, s2
);
181 char *result
= REAL(strstr
)(s1
, s2
);
182 __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1
, s2
, result
);
186 ATTRIBUTE_INTERFACE
char *strcasestr(const char *s1
, const char *s2
) {
187 ensureFuzzerInited();
188 char *result
= REAL(strcasestr
)(s1
, s2
);
189 __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1
, s2
, result
);
194 void *memmem(const void *s1
, size_t len1
, const void *s2
, size_t len2
) {
195 ensureFuzzerInited();
196 void *result
= REAL(memmem
)(s1
, len1
, s2
, len2
);
197 __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1
, len1
, s2
, len2
, result
);
201 __attribute__((section(".preinit_array"),
202 used
)) static void (*__local_fuzzer_preinit
)(void) = fuzzerInit
;
206 static void fuzzerInit() {
207 assert(!FuzzerInitIsRunning
);
210 FuzzerInitIsRunning
= true;
212 REAL(bcmp
) = reinterpret_cast<memcmp_type
>(
213 getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp
)));
214 REAL(memcmp
) = reinterpret_cast<memcmp_type
>(
215 getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp
)));
216 REAL(strncmp
) = reinterpret_cast<strncmp_type
>(
217 getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp
)));
218 REAL(strcmp
) = reinterpret_cast<strcmp_type
>(
219 getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp
)));
220 REAL(strncasecmp
) = reinterpret_cast<strncasecmp_type
>(
221 getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp
)));
222 REAL(strcasecmp
) = reinterpret_cast<strcasecmp_type
>(
223 getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp
)));
224 REAL(strstr
) = reinterpret_cast<strstr_type
>(
225 getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr
)));
226 REAL(strcasestr
) = reinterpret_cast<strcasestr_type
>(
227 getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr
)));
228 REAL(memmem
) = reinterpret_cast<memmem_type
>(
229 getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem
)));
231 FuzzerInitIsRunning
= false;