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.c374
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 */
46typedef unsigned long long fuzz_ullong;
47
48/* For base-64 fuzzing */
49static const char fuzz_b64chars[] =
50 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
51
52struct 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
70static const char *
71fuzz_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
95void
96fuzz_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
170struct fuzz *
171fuzz_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
192void
193fuzz_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
204static int
205fuzz_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
227void
228fuzz_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
324int
325fuzz_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
333size_t
334fuzz_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
353u_char *
354fuzz_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