diff options
Diffstat (limited to 'regress/unittests/test_helper/fuzz.c')
-rw-r--r-- | regress/unittests/test_helper/fuzz.c | 374 |
1 files changed, 374 insertions, 0 deletions
diff --git a/regress/unittests/test_helper/fuzz.c b/regress/unittests/test_helper/fuzz.c new file mode 100644 index 000000000..b64af24ed --- /dev/null +++ b/regress/unittests/test_helper/fuzz.c | |||
@@ -0,0 +1,374 @@ | |||
1 | /* $OpenBSD: fuzz.c,v 1.3 2014/05/02 09:41:32 andre Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2011 Damien Miller <djm@mindrot.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | /* Utility functions/framework for fuzz tests */ | ||
19 | |||
20 | #include <sys/types.h> | ||
21 | |||
22 | #include <assert.h> | ||
23 | #include <ctype.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdint.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <assert.h> | ||
29 | |||
30 | #include "test_helper.h" | ||
31 | |||
32 | /* #define FUZZ_DEBUG */ | ||
33 | |||
34 | #ifdef FUZZ_DEBUG | ||
35 | # define FUZZ_DBG(x) do { \ | ||
36 | printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \ | ||
37 | printf x; \ | ||
38 | printf("\n"); \ | ||
39 | fflush(stdout); \ | ||
40 | } while (0) | ||
41 | #else | ||
42 | # define FUZZ_DBG(x) | ||
43 | #endif | ||
44 | |||
45 | /* For brevity later */ | ||
46 | typedef unsigned long long fuzz_ullong; | ||
47 | |||
48 | /* For base-64 fuzzing */ | ||
49 | static const char fuzz_b64chars[] = | ||
50 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
51 | |||
52 | struct fuzz { | ||
53 | /* Fuzz method currently in use */ | ||
54 | int strategy; | ||
55 | |||
56 | /* Fuzz methods remaining */ | ||
57 | int strategies; | ||
58 | |||
59 | /* Original seed data blob */ | ||
60 | void *seed; | ||
61 | size_t slen; | ||
62 | |||
63 | /* Current working copy of seed with fuzz mutations applied */ | ||
64 | u_char *fuzzed; | ||
65 | |||
66 | /* Used by fuzz methods */ | ||
67 | size_t o1, o2; | ||
68 | }; | ||
69 | |||
70 | static const char * | ||
71 | fuzz_ntop(u_int n) | ||
72 | { | ||
73 | switch (n) { | ||
74 | case 0: | ||
75 | return "NONE"; | ||
76 | case FUZZ_1_BIT_FLIP: | ||
77 | return "FUZZ_1_BIT_FLIP"; | ||
78 | case FUZZ_2_BIT_FLIP: | ||
79 | return "FUZZ_2_BIT_FLIP"; | ||
80 | case FUZZ_1_BYTE_FLIP: | ||
81 | return "FUZZ_1_BYTE_FLIP"; | ||
82 | case FUZZ_2_BYTE_FLIP: | ||
83 | return "FUZZ_2_BYTE_FLIP"; | ||
84 | case FUZZ_TRUNCATE_START: | ||
85 | return "FUZZ_TRUNCATE_START"; | ||
86 | case FUZZ_TRUNCATE_END: | ||
87 | return "FUZZ_TRUNCATE_END"; | ||
88 | case FUZZ_BASE64: | ||
89 | return "FUZZ_BASE64"; | ||
90 | default: | ||
91 | abort(); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | void | ||
96 | fuzz_dump(struct fuzz *fuzz) | ||
97 | { | ||
98 | u_char *p = fuzz_ptr(fuzz); | ||
99 | size_t i, j, len = fuzz_len(fuzz); | ||
100 | |||
101 | switch (fuzz->strategy) { | ||
102 | case FUZZ_1_BIT_FLIP: | ||
103 | fprintf(stderr, "%s case %zu of %zu (bit: %zu)\n", | ||
104 | fuzz_ntop(fuzz->strategy), | ||
105 | fuzz->o1, fuzz->slen * 8, fuzz->o1); | ||
106 | break; | ||
107 | case FUZZ_2_BIT_FLIP: | ||
108 | fprintf(stderr, "%s case %llu of %llu (bits: %zu, %zu)\n", | ||
109 | fuzz_ntop(fuzz->strategy), | ||
110 | (((fuzz_ullong)fuzz->o2) * fuzz->slen * 8) + fuzz->o1, | ||
111 | ((fuzz_ullong)fuzz->slen * 8) * fuzz->slen * 8, | ||
112 | fuzz->o1, fuzz->o2); | ||
113 | break; | ||
114 | case FUZZ_1_BYTE_FLIP: | ||
115 | fprintf(stderr, "%s case %zu of %zu (byte: %zu)\n", | ||
116 | fuzz_ntop(fuzz->strategy), | ||
117 | fuzz->o1, fuzz->slen, fuzz->o1); | ||
118 | break; | ||
119 | case FUZZ_2_BYTE_FLIP: | ||
120 | fprintf(stderr, "%s case %llu of %llu (bytes: %zu, %zu)\n", | ||
121 | fuzz_ntop(fuzz->strategy), | ||
122 | (((fuzz_ullong)fuzz->o2) * fuzz->slen) + fuzz->o1, | ||
123 | ((fuzz_ullong)fuzz->slen) * fuzz->slen, | ||
124 | fuzz->o1, fuzz->o2); | ||
125 | break; | ||
126 | case FUZZ_TRUNCATE_START: | ||
127 | fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n", | ||
128 | fuzz_ntop(fuzz->strategy), | ||
129 | fuzz->o1, fuzz->slen, fuzz->o1); | ||
130 | break; | ||
131 | case FUZZ_TRUNCATE_END: | ||
132 | fprintf(stderr, "%s case %zu of %zu (offset: %zu)\n", | ||
133 | fuzz_ntop(fuzz->strategy), | ||
134 | fuzz->o1, fuzz->slen, fuzz->o1); | ||
135 | break; | ||
136 | case FUZZ_BASE64: | ||
137 | assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1); | ||
138 | fprintf(stderr, "%s case %llu of %llu (offset: %zu char: %c)\n", | ||
139 | fuzz_ntop(fuzz->strategy), | ||
140 | (fuzz->o1 * (fuzz_ullong)64) + fuzz->o2, | ||
141 | fuzz->slen * (fuzz_ullong)64, fuzz->o1, | ||
142 | fuzz_b64chars[fuzz->o2]); | ||
143 | break; | ||
144 | default: | ||
145 | abort(); | ||
146 | } | ||
147 | |||
148 | fprintf(stderr, "fuzz context %p len = %zu\n", fuzz, len); | ||
149 | for (i = 0; i < len; i += 16) { | ||
150 | fprintf(stderr, "%.4zd: ", i); | ||
151 | for (j = i; j < i + 16; j++) { | ||
152 | if (j < len) | ||
153 | fprintf(stderr, "%02x ", p[j]); | ||
154 | else | ||
155 | fprintf(stderr, " "); | ||
156 | } | ||
157 | fprintf(stderr, " "); | ||
158 | for (j = i; j < i + 16; j++) { | ||
159 | if (j < len) { | ||
160 | if (isascii(p[j]) && isprint(p[j])) | ||
161 | fprintf(stderr, "%c", p[j]); | ||
162 | else | ||
163 | fprintf(stderr, "."); | ||
164 | } | ||
165 | } | ||
166 | fprintf(stderr, "\n"); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | struct fuzz * | ||
171 | fuzz_begin(u_int strategies, const void *p, size_t l) | ||
172 | { | ||
173 | struct fuzz *ret = calloc(sizeof(*ret), 1); | ||
174 | |||
175 | assert(p != NULL); | ||
176 | assert(ret != NULL); | ||
177 | ret->seed = malloc(l); | ||
178 | assert(ret->seed != NULL); | ||
179 | memcpy(ret->seed, p, l); | ||
180 | ret->slen = l; | ||
181 | ret->strategies = strategies; | ||
182 | |||
183 | assert(ret->slen < SIZE_MAX / 8); | ||
184 | assert(ret->strategies <= (FUZZ_MAX|(FUZZ_MAX-1))); | ||
185 | |||
186 | FUZZ_DBG(("begin, ret = %p", ret)); | ||
187 | |||
188 | fuzz_next(ret); | ||
189 | return ret; | ||
190 | } | ||
191 | |||
192 | void | ||
193 | fuzz_cleanup(struct fuzz *fuzz) | ||
194 | { | ||
195 | FUZZ_DBG(("cleanup, fuzz = %p", fuzz)); | ||
196 | assert(fuzz != NULL); | ||
197 | assert(fuzz->seed != NULL); | ||
198 | assert(fuzz->fuzzed != NULL); | ||
199 | free(fuzz->seed); | ||
200 | free(fuzz->fuzzed); | ||
201 | free(fuzz); | ||
202 | } | ||
203 | |||
204 | static int | ||
205 | fuzz_strategy_done(struct fuzz *fuzz) | ||
206 | { | ||
207 | FUZZ_DBG(("fuzz = %p, strategy = %s, o1 = %zu, o2 = %zu, slen = %zu", | ||
208 | fuzz, fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->o2, fuzz->slen)); | ||
209 | |||
210 | switch (fuzz->strategy) { | ||
211 | case FUZZ_1_BIT_FLIP: | ||
212 | return fuzz->o1 >= fuzz->slen * 8; | ||
213 | case FUZZ_2_BIT_FLIP: | ||
214 | return fuzz->o2 >= fuzz->slen * 8; | ||
215 | case FUZZ_2_BYTE_FLIP: | ||
216 | return fuzz->o2 >= fuzz->slen; | ||
217 | case FUZZ_1_BYTE_FLIP: | ||
218 | case FUZZ_TRUNCATE_START: | ||
219 | case FUZZ_TRUNCATE_END: | ||
220 | case FUZZ_BASE64: | ||
221 | return fuzz->o1 >= fuzz->slen; | ||
222 | default: | ||
223 | abort(); | ||
224 | } | ||
225 | } | ||
226 | |||
227 | void | ||
228 | fuzz_next(struct fuzz *fuzz) | ||
229 | { | ||
230 | u_int i; | ||
231 | |||
232 | FUZZ_DBG(("start, fuzz = %p, strategy = %s, strategies = 0x%lx, " | ||
233 | "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy), | ||
234 | (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen)); | ||
235 | |||
236 | if (fuzz->strategy == 0 || fuzz_strategy_done(fuzz)) { | ||
237 | /* If we are just starting out, we need to allocate too */ | ||
238 | if (fuzz->fuzzed == NULL) { | ||
239 | FUZZ_DBG(("alloc")); | ||
240 | fuzz->fuzzed = calloc(fuzz->slen, 1); | ||
241 | } | ||
242 | /* Pick next strategy */ | ||
243 | FUZZ_DBG(("advance")); | ||
244 | for (i = 1; i <= FUZZ_MAX; i <<= 1) { | ||
245 | if ((fuzz->strategies & i) != 0) { | ||
246 | fuzz->strategy = i; | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | FUZZ_DBG(("selected = %u", fuzz->strategy)); | ||
251 | if (fuzz->strategy == 0) { | ||
252 | FUZZ_DBG(("done, no more strategies")); | ||
253 | return; | ||
254 | } | ||
255 | fuzz->strategies &= ~(fuzz->strategy); | ||
256 | fuzz->o1 = fuzz->o2 = 0; | ||
257 | } | ||
258 | |||
259 | assert(fuzz->fuzzed != NULL); | ||
260 | |||
261 | switch (fuzz->strategy) { | ||
262 | case FUZZ_1_BIT_FLIP: | ||
263 | assert(fuzz->o1 / 8 < fuzz->slen); | ||
264 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
265 | fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8); | ||
266 | fuzz->o1++; | ||
267 | break; | ||
268 | case FUZZ_2_BIT_FLIP: | ||
269 | assert(fuzz->o1 / 8 < fuzz->slen); | ||
270 | assert(fuzz->o2 / 8 < fuzz->slen); | ||
271 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
272 | fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8); | ||
273 | fuzz->fuzzed[fuzz->o2 / 8] ^= 1 << (fuzz->o2 % 8); | ||
274 | fuzz->o1++; | ||
275 | if (fuzz->o1 >= fuzz->slen * 8) { | ||
276 | fuzz->o1 = 0; | ||
277 | fuzz->o2++; | ||
278 | } | ||
279 | break; | ||
280 | case FUZZ_1_BYTE_FLIP: | ||
281 | assert(fuzz->o1 < fuzz->slen); | ||
282 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
283 | fuzz->fuzzed[fuzz->o1] ^= 0xff; | ||
284 | fuzz->o1++; | ||
285 | break; | ||
286 | case FUZZ_2_BYTE_FLIP: | ||
287 | assert(fuzz->o1 < fuzz->slen); | ||
288 | assert(fuzz->o2 < fuzz->slen); | ||
289 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
290 | fuzz->fuzzed[fuzz->o1] ^= 0xff; | ||
291 | fuzz->fuzzed[fuzz->o2] ^= 0xff; | ||
292 | fuzz->o1++; | ||
293 | if (fuzz->o1 >= fuzz->slen) { | ||
294 | fuzz->o1 = 0; | ||
295 | fuzz->o2++; | ||
296 | } | ||
297 | break; | ||
298 | case FUZZ_TRUNCATE_START: | ||
299 | case FUZZ_TRUNCATE_END: | ||
300 | assert(fuzz->o1 < fuzz->slen); | ||
301 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
302 | fuzz->o1++; | ||
303 | break; | ||
304 | case FUZZ_BASE64: | ||
305 | assert(fuzz->o1 < fuzz->slen); | ||
306 | assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1); | ||
307 | memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); | ||
308 | fuzz->fuzzed[fuzz->o1] = fuzz_b64chars[fuzz->o2]; | ||
309 | fuzz->o2++; | ||
310 | if (fuzz->o2 >= sizeof(fuzz_b64chars) - 1) { | ||
311 | fuzz->o2 = 0; | ||
312 | fuzz->o1++; | ||
313 | } | ||
314 | break; | ||
315 | default: | ||
316 | abort(); | ||
317 | } | ||
318 | |||
319 | FUZZ_DBG(("done, fuzz = %p, strategy = %s, strategies = 0x%lx, " | ||
320 | "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy), | ||
321 | (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen)); | ||
322 | } | ||
323 | |||
324 | int | ||
325 | fuzz_done(struct fuzz *fuzz) | ||
326 | { | ||
327 | FUZZ_DBG(("fuzz = %p, strategies = 0x%lx", fuzz, | ||
328 | (u_long)fuzz->strategies)); | ||
329 | |||
330 | return fuzz_strategy_done(fuzz) && fuzz->strategies == 0; | ||
331 | } | ||
332 | |||
333 | size_t | ||
334 | fuzz_len(struct fuzz *fuzz) | ||
335 | { | ||
336 | assert(fuzz->fuzzed != NULL); | ||
337 | switch (fuzz->strategy) { | ||
338 | case FUZZ_1_BIT_FLIP: | ||
339 | case FUZZ_2_BIT_FLIP: | ||
340 | case FUZZ_1_BYTE_FLIP: | ||
341 | case FUZZ_2_BYTE_FLIP: | ||
342 | case FUZZ_BASE64: | ||
343 | return fuzz->slen; | ||
344 | case FUZZ_TRUNCATE_START: | ||
345 | case FUZZ_TRUNCATE_END: | ||
346 | assert(fuzz->o1 <= fuzz->slen); | ||
347 | return fuzz->slen - fuzz->o1; | ||
348 | default: | ||
349 | abort(); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | u_char * | ||
354 | fuzz_ptr(struct fuzz *fuzz) | ||
355 | { | ||
356 | assert(fuzz->fuzzed != NULL); | ||
357 | switch (fuzz->strategy) { | ||
358 | case FUZZ_1_BIT_FLIP: | ||
359 | case FUZZ_2_BIT_FLIP: | ||
360 | case FUZZ_1_BYTE_FLIP: | ||
361 | case FUZZ_2_BYTE_FLIP: | ||
362 | case FUZZ_BASE64: | ||
363 | return fuzz->fuzzed; | ||
364 | case FUZZ_TRUNCATE_START: | ||
365 | assert(fuzz->o1 <= fuzz->slen); | ||
366 | return fuzz->fuzzed + fuzz->o1; | ||
367 | case FUZZ_TRUNCATE_END: | ||
368 | assert(fuzz->o1 <= fuzz->slen); | ||
369 | return fuzz->fuzzed; | ||
370 | default: | ||
371 | abort(); | ||
372 | } | ||
373 | } | ||
374 | |||