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