1 #include <ctype.h>
2 #include <inttypes.h>
3 #include <stdbool.h>
4 #include <stdint.h>
5 #include <string.h>
6 #include <unistd.h>
7 
8 #include "libhfcommon/common.h"
9 #include "libhfuzz/instrument.h"
10 
11 __attribute__((visibility("default"))) __attribute__((used))
12 const char* const LIBHFUZZ_module_memorycmp = "LIBHFUZZ_module_memorycmp";
13 
14 #define RET_CALL_CHAIN (uintptr_t) __builtin_return_address(0)
15 
HF_strcmp(const char * s1,const char * s2,uintptr_t addr)16 static inline int HF_strcmp(const char* s1, const char* s2, uintptr_t addr) {
17     size_t i;
18     for (i = 0; s1[i] == s2[i]; i++) {
19         if (s1[i] == '\0' || s2[i] == '\0') {
20             break;
21         }
22     }
23     instrumentUpdateCmpMap(addr, i);
24     return ((unsigned char)s1[i] - (unsigned char)s2[i]);
25 }
26 
HF_strcasecmp(const char * s1,const char * s2,uintptr_t addr)27 static inline int HF_strcasecmp(const char* s1, const char* s2, uintptr_t addr) {
28     size_t i;
29     for (i = 0; tolower((unsigned char)s1[i]) == tolower((unsigned char)s2[i]); i++) {
30         if (s1[i] == '\0' || s2[i] == '\0') {
31             break;
32         }
33     }
34     instrumentUpdateCmpMap(addr, i);
35     return (tolower((unsigned char)s1[i]) - tolower((unsigned char)s2[i]));
36 }
37 
HF_strncmp(const char * s1,const char * s2,size_t n,uintptr_t addr)38 static inline int HF_strncmp(const char* s1, const char* s2, size_t n, uintptr_t addr) {
39     size_t i;
40     for (i = 0; i < n; i++) {
41         if ((s1[i] != s2[i]) || s1[i] == '\0' || s2[i] == '\0') {
42             break;
43         }
44     }
45 
46     instrumentUpdateCmpMap(addr, i);
47     if (i == n) {
48         return 0;
49     }
50     return (unsigned char)s1[i] - (unsigned char)s2[i];
51 }
52 
HF_strncasecmp(const char * s1,const char * s2,size_t n,uintptr_t addr)53 static inline int HF_strncasecmp(const char* s1, const char* s2, size_t n, uintptr_t addr) {
54     size_t i;
55     for (i = 0; i < n; i++) {
56         if ((tolower((unsigned char)s1[i]) != tolower((unsigned char)s2[i])) || s1[i] == '\0' ||
57             s2[i] == '\0') {
58             break;
59         }
60     }
61 
62     instrumentUpdateCmpMap(addr, i);
63     if (i == n) {
64         return 0;
65     }
66     return tolower((unsigned char)s1[i]) - tolower((unsigned char)s2[i]);
67 }
68 
HF_strstr(const char * haystack,const char * needle,uintptr_t addr)69 static inline char* HF_strstr(const char* haystack, const char* needle, uintptr_t addr) {
70     size_t needle_len = strlen(needle);
71     if (needle_len == 0) {
72         return (char*)haystack;
73     }
74 
75     const char* h = haystack;
76     for (; (h = strchr(h, needle[0])) != NULL; h++) {
77         if (HF_strncmp(h, needle, needle_len, addr) == 0) {
78             return (char*)h;
79         }
80     }
81     return NULL;
82 }
83 
HF_strcasestr(const char * haystack,const char * needle,uintptr_t addr)84 static inline char* HF_strcasestr(const char* haystack, const char* needle, uintptr_t addr) {
85     size_t needle_len = strlen(needle);
86     for (size_t i = 0; haystack[i]; i++) {
87         if (HF_strncasecmp(&haystack[i], needle, needle_len, addr) == 0) {
88             return (char*)(&haystack[i]);
89         }
90     }
91     return NULL;
92 }
93 
HF_memcmp(const void * m1,const void * m2,size_t n,uintptr_t addr)94 static inline int HF_memcmp(const void* m1, const void* m2, size_t n, uintptr_t addr) {
95     const unsigned char* s1 = (const unsigned char*)m1;
96     const unsigned char* s2 = (const unsigned char*)m2;
97 
98     size_t i;
99     for (i = 0; i < n; i++) {
100         if (s1[i] != s2[i]) {
101             break;
102         }
103     }
104 
105     instrumentUpdateCmpMap(addr, i);
106     if (i == n) {
107         return 0;
108     }
109     return ((unsigned char)s1[i] - (unsigned char)s2[i]);
110 }
111 
HF_memmem(const void * haystack,size_t haystacklen,const void * needle,size_t needlelen,uintptr_t addr)112 static inline void* HF_memmem(const void* haystack, size_t haystacklen, const void* needle,
113     size_t needlelen, uintptr_t addr) {
114     if (needlelen > haystacklen) {
115         return NULL;
116     }
117     if (needlelen == 0) {
118         return (void*)haystack;
119     }
120 
121     const char* h = haystack;
122     for (size_t i = 0; i <= (haystacklen - needlelen); i++) {
123         if (HF_memcmp(&h[i], needle, needlelen, addr) == 0) {
124             return (void*)(&h[i]);
125         }
126     }
127     return NULL;
128 }
129 
HF_strcpy(char * dest,const char * src,uintptr_t addr)130 static inline char* HF_strcpy(char* dest, const char* src, uintptr_t addr) {
131     size_t len = strlen(src);
132 
133     instrumentUpdateCmpMap(addr, len);
134     return memcpy(dest, src, len + 1);
135 }
136 
137 /* Define a weak function x, as well as __wrap_x pointing to x */
138 #define XVAL(x) x
139 #define HF_WEAK_WRAP(ret, func, ...) \
140     _Pragma(HF__XSTR(weak func = __wrap_##func)) XVAL(ret) XVAL(__wrap_##func)(__VA_ARGS__)
141 
142 /* Typical libc wrappers */
HF_WEAK_WRAP(int,strcmp,const char * s1,const char * s2)143 HF_WEAK_WRAP(int, strcmp, const char* s1, const char* s2) {
144     return HF_strcmp(s1, s2, RET_CALL_CHAIN);
145 }
HF_WEAK_WRAP(int,strcasecmp,const char * s1,const char * s2)146 HF_WEAK_WRAP(int, strcasecmp, const char* s1, const char* s2) {
147     return HF_strcasecmp(s1, s2, RET_CALL_CHAIN);
148 }
HF_WEAK_WRAP(int,strncmp,const char * s1,const char * s2,size_t n)149 HF_WEAK_WRAP(int, strncmp, const char* s1, const char* s2, size_t n) {
150     return HF_strncmp(s1, s2, n, RET_CALL_CHAIN);
151 }
HF_WEAK_WRAP(int,strncasecmp,const char * s1,const char * s2,size_t n)152 HF_WEAK_WRAP(int, strncasecmp, const char* s1, const char* s2, size_t n) {
153     return HF_strncasecmp(s1, s2, n, RET_CALL_CHAIN);
154 }
HF_WEAK_WRAP(char *,strstr,const char * haystack,const char * needle)155 HF_WEAK_WRAP(char*, strstr, const char* haystack, const char* needle) {
156     return HF_strstr(haystack, needle, RET_CALL_CHAIN);
157 }
HF_WEAK_WRAP(char *,strcasestr,const char * haystack,const char * needle)158 HF_WEAK_WRAP(char*, strcasestr, const char* haystack, const char* needle) {
159     return HF_strcasestr(haystack, needle, RET_CALL_CHAIN);
160 }
HF_WEAK_WRAP(int,memcmp,const void * m1,const void * m2,size_t n)161 HF_WEAK_WRAP(int, memcmp, const void* m1, const void* m2, size_t n) {
162     return HF_memcmp(m1, m2, n, RET_CALL_CHAIN);
163 }
HF_WEAK_WRAP(int,bcmp,const void * m1,const void * m2,size_t n)164 HF_WEAK_WRAP(int, bcmp, const void* m1, const void* m2, size_t n) {
165     return HF_memcmp(m1, m2, n, RET_CALL_CHAIN);
166 }
HF_WEAK_WRAP(void *,memmem,const void * haystack,size_t haystacklen,const void * needle,size_t needlelen)167 HF_WEAK_WRAP(
168     void*, memmem, const void* haystack, size_t haystacklen, const void* needle, size_t needlelen) {
169     return HF_memmem(haystack, haystacklen, needle, needlelen, RET_CALL_CHAIN);
170 }
HF_WEAK_WRAP(char *,strcpy,char * dest,const char * src)171 HF_WEAK_WRAP(char*, strcpy, char* dest, const char* src) {
172     return HF_strcpy(dest, src, RET_CALL_CHAIN);
173 }
174 
175 /*
176  * Apache's httpd wrappers
177  */
HF_WEAK_WRAP(int,ap_cstr_casecmp,const char * s1,const char * s2)178 HF_WEAK_WRAP(int, ap_cstr_casecmp, const char* s1, const char* s2) {
179     return HF_strcasecmp(s1, s2, RET_CALL_CHAIN);
180 }
181 
HF_WEAK_WRAP(int,ap_cstr_casecmpn,const char * s1,const char * s2,size_t n)182 HF_WEAK_WRAP(int, ap_cstr_casecmpn, const char* s1, const char* s2, size_t n) {
183     return HF_strncasecmp(s1, s2, n, RET_CALL_CHAIN);
184 }
185 
HF_WEAK_WRAP(const char *,ap_strcasestr,const char * s1,const char * s2)186 HF_WEAK_WRAP(const char*, ap_strcasestr, const char* s1, const char* s2) {
187     return HF_strcasestr(s1, s2, RET_CALL_CHAIN);
188 }
189 
HF_WEAK_WRAP(int,apr_cstr_casecmp,const char * s1,const char * s2)190 HF_WEAK_WRAP(int, apr_cstr_casecmp, const char* s1, const char* s2) {
191     return HF_strcasecmp(s1, s2, RET_CALL_CHAIN);
192 }
193 
HF_WEAK_WRAP(int,apr_cstr_casecmpn,const char * s1,const char * s2,size_t n)194 HF_WEAK_WRAP(int, apr_cstr_casecmpn, const char* s1, const char* s2, size_t n) {
195     return HF_strncasecmp(s1, s2, n, RET_CALL_CHAIN);
196 }
197 
198 /*
199  * *SSL wrappers
200  */
HF_WEAK_WRAP(int,CRYPTO_memcmp,const void * m1,const void * m2,size_t len)201 HF_WEAK_WRAP(int, CRYPTO_memcmp, const void* m1, const void* m2, size_t len) {
202     return HF_memcmp(m1, m2, len, RET_CALL_CHAIN);
203 }
204 
HF_WEAK_WRAP(int,OPENSSL_memcmp,const void * m1,const void * m2,size_t len)205 HF_WEAK_WRAP(int, OPENSSL_memcmp, const void* m1, const void* m2, size_t len) {
206     return HF_memcmp(m1, m2, len, RET_CALL_CHAIN);
207 }
208 
HF_WEAK_WRAP(int,OPENSSL_strcasecmp,const char * s1,const char * s2)209 HF_WEAK_WRAP(int, OPENSSL_strcasecmp, const char* s1, const char* s2) {
210     return HF_strcasecmp(s1, s2, RET_CALL_CHAIN);
211 }
212 
HF_WEAK_WRAP(int,OPENSSL_strncasecmp,const char * s1,const char * s2,size_t len)213 HF_WEAK_WRAP(int, OPENSSL_strncasecmp, const char* s1, const char* s2, size_t len) {
214     return HF_strncasecmp(s1, s2, len, RET_CALL_CHAIN);
215 }
216 
HF_WEAK_WRAP(int32_t,memcmpct,const void * s1,const void * s2,size_t len)217 HF_WEAK_WRAP(int32_t, memcmpct, const void* s1, const void* s2, size_t len) {
218     return HF_memcmp(s1, s2, len, RET_CALL_CHAIN);
219 }
220 
221 /*
222  * libXML wrappers
223  */
HF_WEAK_WRAP(int,xmlStrncmp,const char * s1,const char * s2,int len)224 HF_WEAK_WRAP(int, xmlStrncmp, const char* s1, const char* s2, int len) {
225     if (len <= 0) {
226         return 0;
227     }
228     if (s1 == s2) {
229         return 0;
230     }
231     if (s1 == NULL) {
232         return -1;
233     }
234     if (s2 == NULL) {
235         return 1;
236     }
237     return HF_strncmp(s1, s2, (size_t)len, RET_CALL_CHAIN);
238 }
239 
HF_WEAK_WRAP(int,xmlStrcmp,const char * s1,const char * s2)240 HF_WEAK_WRAP(int, xmlStrcmp, const char* s1, const char* s2) {
241     if (s1 == s2) {
242         return 0;
243     }
244     if (s1 == NULL) {
245         return -1;
246     }
247     if (s2 == NULL) {
248         return 1;
249     }
250     return HF_strcmp(s1, s2, RET_CALL_CHAIN);
251 }
252 
HF_WEAK_WRAP(int,xmlStrEqual,const char * s1,const char * s2)253 HF_WEAK_WRAP(int, xmlStrEqual, const char* s1, const char* s2) {
254     if (s1 == s2) {
255         return 1;
256     }
257     if (s1 == NULL) {
258         return 0;
259     }
260     if (s2 == NULL) {
261         return 0;
262     }
263     if (HF_strcmp(s1, s2, RET_CALL_CHAIN) == 0) {
264         return 1;
265     }
266     return 0;
267 }
268 
HF_WEAK_WRAP(int,xmlStrcasecmp,const char * s1,const char * s2)269 HF_WEAK_WRAP(int, xmlStrcasecmp, const char* s1, const char* s2) {
270     if (s1 == s2) {
271         return 0;
272     }
273     if (s1 == NULL) {
274         return -1;
275     }
276     if (s2 == NULL) {
277         return 1;
278     }
279     return HF_strcasecmp(s1, s2, RET_CALL_CHAIN);
280 }
281 
HF_WEAK_WRAP(int,xmlStrncasecmp,const char * s1,const char * s2,int len)282 HF_WEAK_WRAP(int, xmlStrncasecmp, const char* s1, const char* s2, int len) {
283     if (len <= 0) {
284         return 0;
285     }
286     if (s1 == s2) {
287         return 0;
288     }
289     if (s1 == NULL) {
290         return -1;
291     }
292     if (s2 == NULL) {
293         return 1;
294     }
295     return HF_strncasecmp(s1, s2, (size_t)len, RET_CALL_CHAIN);
296 }
297 
HF_WEAK_WRAP(const char *,xmlStrstr,const char * haystack,const char * needle)298 HF_WEAK_WRAP(const char*, xmlStrstr, const char* haystack, const char* needle) {
299     if (haystack == NULL) {
300         return NULL;
301     }
302     if (needle == NULL) {
303         return NULL;
304     }
305     return HF_strstr(haystack, needle, RET_CALL_CHAIN);
306 }
307 
HF_WEAK_WRAP(const char *,xmlStrcasestr,const char * haystack,const char * needle)308 HF_WEAK_WRAP(const char*, xmlStrcasestr, const char* haystack, const char* needle) {
309     if (haystack == NULL) {
310         return NULL;
311     }
312     if (needle == NULL) {
313         return NULL;
314     }
315     return HF_strcasestr(haystack, needle, RET_CALL_CHAIN);
316 }
317 
318 /*
319  * Samba wrappers
320  */
HF_WEAK_WRAP(int,memcmp_const_time,const void * s1,const void * s2,size_t n)321 HF_WEAK_WRAP(int, memcmp_const_time, const void* s1, const void* s2, size_t n) {
322     return HF_memcmp(s1, s2, n, RET_CALL_CHAIN);
323 }
324 
HF_WEAK_WRAP(bool,strcsequal,const void * s1,const void * s2)325 HF_WEAK_WRAP(bool, strcsequal, const void* s1, const void* s2) {
326     if (s1 == s2) {
327         return true;
328     }
329     if (!s1 || !s2) {
330         return false;
331     }
332     return (HF_strcmp(s1, s2, RET_CALL_CHAIN) == 0);
333 }
334