xref: /openbsd/regress/sbin/iked/test_helper/fuzz.c (revision 09467b48)
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 #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, 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 
375