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