1 /* $OpenBSD: fuzz.c,v 1.8 2015/03/03 20:42:49 djm Exp $ */
3 * Copyright (c) 2011 Damien Miller <djm@mindrot.org>
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.
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.
18 /* Utility functions/framework for fuzz tests */
22 #include <sys/types.h>
36 #include "test_helper.h"
39 /* #define FUZZ_DEBUG */
42 # define FUZZ_DBG(x) do { \
43 printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \
52 /* For brevity later */
53 typedef unsigned long long fuzz_ullong;
55 /* For base-64 fuzzing */
56 static const char fuzz_b64chars[] =
57 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60 /* Fuzz method currently in use */
63 /* Fuzz methods remaining */
66 /* Original seed data blob */
70 /* Current working copy of seed with fuzz mutations applied */
73 /* Used by fuzz methods */
84 return "FUZZ_1_BIT_FLIP";
86 return "FUZZ_2_BIT_FLIP";
87 case FUZZ_1_BYTE_FLIP:
88 return "FUZZ_1_BYTE_FLIP";
89 case FUZZ_2_BYTE_FLIP:
90 return "FUZZ_2_BYTE_FLIP";
91 case FUZZ_TRUNCATE_START:
92 return "FUZZ_TRUNCATE_START";
93 case FUZZ_TRUNCATE_END:
94 return "FUZZ_TRUNCATE_END";
103 fuzz_fmt(struct fuzz *fuzz, char *s, size_t n)
108 switch (fuzz->strategy) {
109 case FUZZ_1_BIT_FLIP:
110 snprintf(s, n, "%s case %zu of %zu (bit: %zu)\n",
111 fuzz_ntop(fuzz->strategy),
112 fuzz->o1, fuzz->slen * 8, fuzz->o1);
114 case FUZZ_2_BIT_FLIP:
115 snprintf(s, n, "%s case %llu of %llu (bits: %zu, %zu)\n",
116 fuzz_ntop(fuzz->strategy),
117 (((fuzz_ullong)fuzz->o2) * fuzz->slen * 8) + fuzz->o1,
118 ((fuzz_ullong)fuzz->slen * 8) * fuzz->slen * 8,
121 case FUZZ_1_BYTE_FLIP:
122 snprintf(s, n, "%s case %zu of %zu (byte: %zu)\n",
123 fuzz_ntop(fuzz->strategy),
124 fuzz->o1, fuzz->slen, fuzz->o1);
126 case FUZZ_2_BYTE_FLIP:
127 snprintf(s, n, "%s case %llu of %llu (bytes: %zu, %zu)\n",
128 fuzz_ntop(fuzz->strategy),
129 (((fuzz_ullong)fuzz->o2) * fuzz->slen) + fuzz->o1,
130 ((fuzz_ullong)fuzz->slen) * fuzz->slen,
133 case FUZZ_TRUNCATE_START:
134 snprintf(s, n, "%s case %zu of %zu (offset: %zu)\n",
135 fuzz_ntop(fuzz->strategy),
136 fuzz->o1, fuzz->slen, fuzz->o1);
138 case FUZZ_TRUNCATE_END:
139 snprintf(s, n, "%s case %zu of %zu (offset: %zu)\n",
140 fuzz_ntop(fuzz->strategy),
141 fuzz->o1, fuzz->slen, fuzz->o1);
144 assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
145 snprintf(s, n, "%s case %llu of %llu (offset: %zu char: %c)\n",
146 fuzz_ntop(fuzz->strategy),
147 (fuzz->o1 * (fuzz_ullong)64) + fuzz->o2,
148 fuzz->slen * (fuzz_ullong)64, fuzz->o1,
149 fuzz_b64chars[fuzz->o2]);
158 dump(u_char *p, size_t len)
162 for (i = 0; i < len; i += 16) {
163 fprintf(stderr, "%.4zd: ", i);
164 for (j = i; j < i + 16; j++) {
166 fprintf(stderr, "%02x ", p[j]);
168 fprintf(stderr, " ");
170 fprintf(stderr, " ");
171 for (j = i; j < i + 16; j++) {
173 if (isascii(p[j]) && isprint(p[j]))
174 fprintf(stderr, "%c", p[j]);
176 fprintf(stderr, ".");
179 fprintf(stderr, "\n");
184 fuzz_dump(struct fuzz *fuzz)
188 if (fuzz_fmt(fuzz, buf, sizeof(buf)) != 0) {
189 fprintf(stderr, "%s: fuzz invalid\n", __func__);
193 fprintf(stderr, "fuzz original %p len = %zu\n", fuzz->seed, fuzz->slen);
194 dump(fuzz->seed, fuzz->slen);
195 fprintf(stderr, "fuzz context %p len = %zu\n", fuzz, fuzz_len(fuzz));
196 dump(fuzz_ptr(fuzz), fuzz_len(fuzz));
200 static struct fuzz *last_fuzz;
203 siginfo(int unused __attribute__((__unused__)))
207 test_info(buf, sizeof(buf));
208 atomicio(vwrite, STDERR_FILENO, buf, strlen(buf));
209 if (last_fuzz != NULL) {
210 fuzz_fmt(last_fuzz, buf, sizeof(buf));
211 atomicio(vwrite, STDERR_FILENO, buf, strlen(buf));
217 fuzz_begin(u_int strategies, const void *p, size_t l)
219 struct fuzz *ret = calloc(sizeof(*ret), 1);
223 ret->seed = malloc(l);
224 assert(ret->seed != NULL);
225 memcpy(ret->seed, p, l);
227 ret->strategies = strategies;
229 assert(ret->slen < SIZE_MAX / 8);
230 assert(ret->strategies <= (FUZZ_MAX|(FUZZ_MAX-1)));
232 FUZZ_DBG(("begin, ret = %p", ret));
238 signal(SIGINFO, siginfo);
245 fuzz_cleanup(struct fuzz *fuzz)
247 FUZZ_DBG(("cleanup, fuzz = %p", fuzz));
250 signal(SIGINFO, SIG_DFL);
252 assert(fuzz != NULL);
253 assert(fuzz->seed != NULL);
254 assert(fuzz->fuzzed != NULL);
261 fuzz_strategy_done(struct fuzz *fuzz)
263 FUZZ_DBG(("fuzz = %p, strategy = %s, o1 = %zu, o2 = %zu, slen = %zu",
264 fuzz, fuzz_ntop(fuzz->strategy), fuzz->o1, fuzz->o2, fuzz->slen));
266 switch (fuzz->strategy) {
267 case FUZZ_1_BIT_FLIP:
268 return fuzz->o1 >= fuzz->slen * 8;
269 case FUZZ_2_BIT_FLIP:
270 return fuzz->o2 >= fuzz->slen * 8;
271 case FUZZ_2_BYTE_FLIP:
272 return fuzz->o2 >= fuzz->slen;
273 case FUZZ_1_BYTE_FLIP:
274 case FUZZ_TRUNCATE_START:
275 case FUZZ_TRUNCATE_END:
277 return fuzz->o1 >= fuzz->slen;
284 fuzz_next(struct fuzz *fuzz)
288 FUZZ_DBG(("start, fuzz = %p, strategy = %s, strategies = 0x%lx, "
289 "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
290 (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
292 if (fuzz->strategy == 0 || fuzz_strategy_done(fuzz)) {
293 /* If we are just starting out, we need to allocate too */
294 if (fuzz->fuzzed == NULL) {
296 fuzz->fuzzed = calloc(fuzz->slen, 1);
298 /* Pick next strategy */
299 FUZZ_DBG(("advance"));
300 for (i = 1; i <= FUZZ_MAX; i <<= 1) {
301 if ((fuzz->strategies & i) != 0) {
306 FUZZ_DBG(("selected = %u", fuzz->strategy));
307 if (fuzz->strategy == 0) {
308 FUZZ_DBG(("done, no more strategies"));
311 fuzz->strategies &= ~(fuzz->strategy);
312 fuzz->o1 = fuzz->o2 = 0;
315 assert(fuzz->fuzzed != NULL);
317 switch (fuzz->strategy) {
318 case FUZZ_1_BIT_FLIP:
319 assert(fuzz->o1 / 8 < fuzz->slen);
320 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
321 fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
324 case FUZZ_2_BIT_FLIP:
325 assert(fuzz->o1 / 8 < fuzz->slen);
326 assert(fuzz->o2 / 8 < fuzz->slen);
327 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
328 fuzz->fuzzed[fuzz->o1 / 8] ^= 1 << (fuzz->o1 % 8);
329 fuzz->fuzzed[fuzz->o2 / 8] ^= 1 << (fuzz->o2 % 8);
331 if (fuzz->o1 >= fuzz->slen * 8) {
336 case FUZZ_1_BYTE_FLIP:
337 assert(fuzz->o1 < fuzz->slen);
338 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
339 fuzz->fuzzed[fuzz->o1] ^= 0xff;
342 case FUZZ_2_BYTE_FLIP:
343 assert(fuzz->o1 < fuzz->slen);
344 assert(fuzz->o2 < fuzz->slen);
345 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
346 fuzz->fuzzed[fuzz->o1] ^= 0xff;
347 fuzz->fuzzed[fuzz->o2] ^= 0xff;
349 if (fuzz->o1 >= fuzz->slen) {
354 case FUZZ_TRUNCATE_START:
355 case FUZZ_TRUNCATE_END:
356 assert(fuzz->o1 < fuzz->slen);
357 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
361 assert(fuzz->o1 < fuzz->slen);
362 assert(fuzz->o2 < sizeof(fuzz_b64chars) - 1);
363 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen);
364 fuzz->fuzzed[fuzz->o1] = fuzz_b64chars[fuzz->o2];
366 if (fuzz->o2 >= sizeof(fuzz_b64chars) - 1) {
375 FUZZ_DBG(("done, fuzz = %p, strategy = %s, strategies = 0x%lx, "
376 "o1 = %zu, o2 = %zu, slen = %zu", fuzz, fuzz_ntop(fuzz->strategy),
377 (u_long)fuzz->strategies, fuzz->o1, fuzz->o2, fuzz->slen));
381 fuzz_matches_original(struct fuzz *fuzz)
383 if (fuzz_len(fuzz) != fuzz->slen)
385 return memcmp(fuzz_ptr(fuzz), fuzz->seed, fuzz->slen) == 0;
389 fuzz_done(struct fuzz *fuzz)
391 FUZZ_DBG(("fuzz = %p, strategies = 0x%lx", fuzz,
392 (u_long)fuzz->strategies));
394 return fuzz_strategy_done(fuzz) && fuzz->strategies == 0;
398 fuzz_len(struct fuzz *fuzz)
400 assert(fuzz->fuzzed != NULL);
401 switch (fuzz->strategy) {
402 case FUZZ_1_BIT_FLIP:
403 case FUZZ_2_BIT_FLIP:
404 case FUZZ_1_BYTE_FLIP:
405 case FUZZ_2_BYTE_FLIP:
408 case FUZZ_TRUNCATE_START:
409 case FUZZ_TRUNCATE_END:
410 assert(fuzz->o1 <= fuzz->slen);
411 return fuzz->slen - fuzz->o1;
418 fuzz_ptr(struct fuzz *fuzz)
420 assert(fuzz->fuzzed != NULL);
421 switch (fuzz->strategy) {
422 case FUZZ_1_BIT_FLIP:
423 case FUZZ_2_BIT_FLIP:
424 case FUZZ_1_BYTE_FLIP:
425 case FUZZ_2_BYTE_FLIP:
428 case FUZZ_TRUNCATE_START:
429 assert(fuzz->o1 <= fuzz->slen);
430 return fuzz->fuzzed + fuzz->o1;
431 case FUZZ_TRUNCATE_END:
432 assert(fuzz->o1 <= fuzz->slen);