xref: /openbsd-src/regress/sbin/iked/test_helper/fuzz.c (revision 6bae335dd015f9e023db26fea05e06c52cf1d0d7)
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