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