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