1 /* $OpenBSD: fuzz.c,v 1.8 2015/03/03 20:42:49 djm 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 "includes.h" 21 22 #include <sys/types.h> 23 #include <sys/uio.h> 24 25 #include <assert.h> 26 #include <ctype.h> 27 #include <stdio.h> 28 #ifdef HAVE_STDINT_H 29 # include <stdint.h> 30 #endif 31 #include <stdlib.h> 32 #include <string.h> 33 #include <signal.h> 34 #include <unistd.h> 35 36 #include "test_helper.h" 37 #include "atomicio.h" 38 39 /* #define FUZZ_DEBUG */ 40 41 #ifdef FUZZ_DEBUG 42 # define FUZZ_DBG(x) do { \ 43 printf("%s:%d %s: ", __FILE__, __LINE__, __func__); \ 44 printf x; \ 45 printf("\n"); \ 46 fflush(stdout); \ 47 } while (0) 48 #else 49 # define FUZZ_DBG(x) 50 #endif 51 52 /* For brevity later */ 53 typedef unsigned long long fuzz_ullong; 54 55 /* For base-64 fuzzing */ 56 static const char fuzz_b64chars[] = 57 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 58 59 struct fuzz { 60 /* Fuzz method currently in use */ 61 int strategy; 62 63 /* Fuzz methods remaining */ 64 int strategies; 65 66 /* Original seed data blob */ 67 void *seed; 68 size_t slen; 69 70 /* Current working copy of seed with fuzz mutations applied */ 71 u_char *fuzzed; 72 73 /* Used by fuzz methods */ 74 size_t o1, o2; 75 }; 76 77 static const char * 78 fuzz_ntop(u_int n) 79 { 80 switch (n) { 81 case 0: 82 return "NONE"; 83 case FUZZ_1_BIT_FLIP: 84 return "FUZZ_1_BIT_FLIP"; 85 case FUZZ_2_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"; 95 case FUZZ_BASE64: 96 return "FUZZ_BASE64"; 97 default: 98 abort(); 99 } 100 } 101 102 static int 103 fuzz_fmt(struct fuzz *fuzz, char *s, size_t n) 104 { 105 if (fuzz == NULL) 106 return -1; 107 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); 113 return 0; 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, 119 fuzz->o1, fuzz->o2); 120 return 0; 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); 125 return 0; 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, 131 fuzz->o1, fuzz->o2); 132 return 0; 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); 137 return 0; 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); 142 return 0; 143 case FUZZ_BASE64: 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]); 150 return 0; 151 default: 152 return -1; 153 abort(); 154 } 155 } 156 157 static void 158 dump(u_char *p, size_t len) 159 { 160 size_t i, j; 161 162 for (i = 0; i < len; i += 16) { 163 fprintf(stderr, "%.4zd: ", i); 164 for (j = i; j < i + 16; j++) { 165 if (j < len) 166 fprintf(stderr, "%02x ", p[j]); 167 else 168 fprintf(stderr, " "); 169 } 170 fprintf(stderr, " "); 171 for (j = i; j < i + 16; j++) { 172 if (j < len) { 173 if (isascii(p[j]) && isprint(p[j])) 174 fprintf(stderr, "%c", p[j]); 175 else 176 fprintf(stderr, "."); 177 } 178 } 179 fprintf(stderr, "\n"); 180 } 181 } 182 183 void 184 fuzz_dump(struct fuzz *fuzz) 185 { 186 char buf[256]; 187 188 if (fuzz_fmt(fuzz, buf, sizeof(buf)) != 0) { 189 fprintf(stderr, "%s: fuzz invalid\n", __func__); 190 abort(); 191 } 192 fputs(buf, stderr); 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)); 197 } 198 199 static struct fuzz *last_fuzz; 200 201 static void 202 siginfo(int unused __attribute__((__unused__))) 203 { 204 char buf[256]; 205 206 test_info(buf, sizeof(buf)); 207 atomicio(vwrite, STDERR_FILENO, buf, strlen(buf)); 208 if (last_fuzz != NULL) { 209 fuzz_fmt(last_fuzz, buf, sizeof(buf)); 210 atomicio(vwrite, STDERR_FILENO, buf, strlen(buf)); 211 } 212 } 213 214 struct fuzz * 215 fuzz_begin(u_int strategies, const void *p, size_t l) 216 { 217 struct fuzz *ret = calloc(sizeof(*ret), 1); 218 219 assert(p != NULL); 220 assert(ret != NULL); 221 ret->seed = malloc(l); 222 assert(ret->seed != NULL); 223 memcpy(ret->seed, p, l); 224 ret->slen = l; 225 ret->strategies = strategies; 226 227 assert(ret->slen < SIZE_MAX / 8); 228 assert(ret->strategies <= (FUZZ_MAX|(FUZZ_MAX-1))); 229 230 FUZZ_DBG(("begin, ret = %p", ret)); 231 232 fuzz_next(ret); 233 234 last_fuzz = ret; 235 #ifdef SIGINFO 236 signal(SIGINFO, siginfo); 237 #endif 238 signal(SIGUSR1, siginfo); 239 240 return ret; 241 } 242 243 void 244 fuzz_cleanup(struct fuzz *fuzz) 245 { 246 FUZZ_DBG(("cleanup, fuzz = %p", fuzz)); 247 last_fuzz = NULL; 248 #ifdef SIGINFO 249 signal(SIGINFO, SIG_DFL); 250 #endif 251 signal(SIGUSR1, SIG_DFL); 252 assert(fuzz != NULL); 253 assert(fuzz->seed != NULL); 254 assert(fuzz->fuzzed != NULL); 255 free(fuzz->seed); 256 free(fuzz->fuzzed); 257 free(fuzz); 258 } 259 260 static int 261 fuzz_strategy_done(struct fuzz *fuzz) 262 { 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)); 265 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: 276 case FUZZ_BASE64: 277 return fuzz->o1 >= fuzz->slen; 278 default: 279 abort(); 280 } 281 } 282 283 void 284 fuzz_next(struct fuzz *fuzz) 285 { 286 u_int i; 287 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)); 291 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) { 295 FUZZ_DBG(("alloc")); 296 fuzz->fuzzed = calloc(fuzz->slen, 1); 297 } 298 /* Pick next strategy */ 299 FUZZ_DBG(("advance")); 300 for (i = 1; i <= FUZZ_MAX; i <<= 1) { 301 if ((fuzz->strategies & i) != 0) { 302 fuzz->strategy = i; 303 break; 304 } 305 } 306 FUZZ_DBG(("selected = %u", fuzz->strategy)); 307 if (fuzz->strategy == 0) { 308 FUZZ_DBG(("done, no more strategies")); 309 return; 310 } 311 fuzz->strategies &= ~(fuzz->strategy); 312 fuzz->o1 = fuzz->o2 = 0; 313 } 314 315 assert(fuzz->fuzzed != NULL); 316 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); 322 fuzz->o1++; 323 break; 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); 330 fuzz->o1++; 331 if (fuzz->o1 >= fuzz->slen * 8) { 332 fuzz->o1 = 0; 333 fuzz->o2++; 334 } 335 break; 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; 340 fuzz->o1++; 341 break; 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; 348 fuzz->o1++; 349 if (fuzz->o1 >= fuzz->slen) { 350 fuzz->o1 = 0; 351 fuzz->o2++; 352 } 353 break; 354 case FUZZ_TRUNCATE_START: 355 case FUZZ_TRUNCATE_END: 356 assert(fuzz->o1 < fuzz->slen); 357 memcpy(fuzz->fuzzed, fuzz->seed, fuzz->slen); 358 fuzz->o1++; 359 break; 360 case FUZZ_BASE64: 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]; 365 fuzz->o2++; 366 if (fuzz->o2 >= sizeof(fuzz_b64chars) - 1) { 367 fuzz->o2 = 0; 368 fuzz->o1++; 369 } 370 break; 371 default: 372 abort(); 373 } 374 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)); 378 } 379 380 int 381 fuzz_matches_original(struct fuzz *fuzz) 382 { 383 if (fuzz_len(fuzz) != fuzz->slen) 384 return 0; 385 return memcmp(fuzz_ptr(fuzz), fuzz->seed, fuzz->slen) == 0; 386 } 387 388 int 389 fuzz_done(struct fuzz *fuzz) 390 { 391 FUZZ_DBG(("fuzz = %p, strategies = 0x%lx", fuzz, 392 (u_long)fuzz->strategies)); 393 394 return fuzz_strategy_done(fuzz) && fuzz->strategies == 0; 395 } 396 397 size_t 398 fuzz_len(struct fuzz *fuzz) 399 { 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: 406 case FUZZ_BASE64: 407 return fuzz->slen; 408 case FUZZ_TRUNCATE_START: 409 case FUZZ_TRUNCATE_END: 410 assert(fuzz->o1 <= fuzz->slen); 411 return fuzz->slen - fuzz->o1; 412 default: 413 abort(); 414 } 415 } 416 417 u_char * 418 fuzz_ptr(struct fuzz *fuzz) 419 { 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: 426 case FUZZ_BASE64: 427 return fuzz->fuzzed; 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); 433 return fuzz->fuzzed; 434 default: 435 abort(); 436 } 437 } 438 439