diff options
author | Andrea Fioraldi <andreafioraldi@gmail.com> | 2019-09-02 18:41:27 +0200 |
---|---|---|
committer | Andrea Fioraldi <andreafioraldi@gmail.com> | 2019-09-02 18:41:27 +0200 |
commit | e9d968e060f59df634409d2bbe58c279cf6eca00 (patch) | |
tree | d3da0cd90c8fd6c093c5f1364786caf62b78a28c /src/afl-fuzz-bitmap.c | |
parent | 1652831f1de2fcf13184162503bb764bd610914c (diff) | |
download | afl++-e9d968e060f59df634409d2bbe58c279cf6eca00.tar.gz |
afl-fuzz.c completely splitted
Diffstat (limited to 'src/afl-fuzz-bitmap.c')
-rw-r--r-- | src/afl-fuzz-bitmap.c | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 6cd9852f..1a77dc13 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -408,3 +408,296 @@ void minimize_bits(u8* dst, u8* src) { } + +#ifndef SIMPLE_FILES + +/* Construct a file name for a new test case, capturing the operation + that led to its discovery. Uses a static buffer. */ + +u8* describe_op(u8 hnb) { + + static u8 ret[256]; + + if (syncing_party) { + + sprintf(ret, "sync:%s,src:%06u", syncing_party, syncing_case); + + } else { + + sprintf(ret, "src:%06u", current_entry); + + sprintf(ret + strlen(ret), ",time:%llu", get_cur_time() - start_time); + + if (splicing_with >= 0) + sprintf(ret + strlen(ret), "+%06d", splicing_with); + + sprintf(ret + strlen(ret), ",op:%s", stage_short); + + if (stage_cur_byte >= 0) { + + sprintf(ret + strlen(ret), ",pos:%d", stage_cur_byte); + + if (stage_val_type != STAGE_VAL_NONE) + sprintf(ret + strlen(ret), ",val:%s%+d", + (stage_val_type == STAGE_VAL_BE) ? "be:" : "", + stage_cur_val); + + } else sprintf(ret + strlen(ret), ",rep:%d", stage_cur_val); + + } + + if (hnb == 2) strcat(ret, ",+cov"); + + return ret; + +} + +#endif /* !SIMPLE_FILES */ + + +/* Write a message accompanying the crash directory :-) */ + +static void write_crash_readme(void) { + + u8* fn = alloc_printf("%s/crashes/README.txt", out_dir); + s32 fd; + FILE* f; + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + ck_free(fn); + + /* Do not die on errors here - that would be impolite. */ + + if (fd < 0) return; + + f = fdopen(fd, "w"); + + if (!f) { + close(fd); + return; + } + + fprintf(f, "Command line used to find this crash:\n\n" + + "%s\n\n" + + "If you can't reproduce a bug outside of afl-fuzz, be sure to set the same\n" + "memory limit. The limit used for this fuzzing session was %s.\n\n" + + "Need a tool to minimize test cases before investigating the crashes or sending\n" + "them to a vendor? Check out the afl-tmin that comes with the fuzzer!\n\n" + + "Found any cool bugs in open-source tools using afl-fuzz? If yes, please drop\n" + "an mail at <afl-users@googlegroups.com> once the issues are fixed\n\n" + + " https://github.com/vanhauser-thc/AFLplusplus\n\n", + + orig_cmdline, DMS(mem_limit << 20)); /* ignore errors */ + + fclose(f); + +} + + +/* Check if the result of an execve() during routine fuzzing is interesting, + save or queue the input test case for further analysis if so. Returns 1 if + entry is saved, 0 otherwise. */ + +u8 save_if_interesting(char** argv, void* mem, u32 len, u8 fault) { + + if (len == 0) return 0; + + u8 *fn = ""; + u8 hnb; + s32 fd; + u8 keeping = 0, res; + + /* Update path frequency. */ + u32 cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + + struct queue_entry* q = queue; + while (q) { + if (q->exec_cksum == cksum) + q->n_fuzz = q->n_fuzz + 1; + + q = q->next; + + } + + if (fault == crash_mode) { + + /* Keep only if there are new bits in the map, add to queue for + future fuzzing, etc. */ + + if (!(hnb = has_new_bits(virgin_bits))) { + if (crash_mode) ++total_crashes; + return 0; + } + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/queue/id:%06u,%s", out_dir, queued_paths, + describe_op(hnb)); + +#else + + fn = alloc_printf("%s/queue/id_%06u", out_dir, queued_paths); + +#endif /* ^!SIMPLE_FILES */ + + add_to_queue(fn, len, 0); + + if (hnb == 2) { + queue_top->has_new_cov = 1; + ++queued_with_cov; + } + + queue_top->exec_cksum = cksum; + + /* Try to calibrate inline; this also calls update_bitmap_score() when + successful. */ + + res = calibrate_case(argv, queue_top, mem, queue_cycle - 1, 0); + + if (res == FAULT_ERROR) + FATAL("Unable to execute target application"); + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + ck_write(fd, mem, len, fn); + close(fd); + + keeping = 1; + + } + + switch (fault) { + + case FAULT_TMOUT: + + /* Timeouts are not very interesting, but we're still obliged to keep + a handful of samples. We use the presence of new bits in the + hang-specific bitmap as a signal of uniqueness. In "dumb" mode, we + just keep everything. */ + + ++total_tmouts; + + if (unique_hangs >= KEEP_UNIQUE_HANG) return keeping; + + if (!dumb_mode) { + +#ifdef __x86_64__ + simplify_trace((u64*)trace_bits); +#else + simplify_trace((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + if (!has_new_bits(virgin_tmout)) return keeping; + + } + + ++unique_tmouts; + + /* Before saving, we make sure that it's a genuine hang by re-running + the target with a more generous timeout (unless the default timeout + is already generous). */ + + if (exec_tmout < hang_tmout) { + + u8 new_fault; + write_to_testcase(mem, len); + new_fault = run_target(argv, hang_tmout); + + /* A corner case that one user reported bumping into: increasing the + timeout actually uncovers a crash. Make sure we don't discard it if + so. */ + + if (!stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash; + + if (stop_soon || new_fault != FAULT_TMOUT) return keeping; + + } + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/hangs/id:%06llu,%s", out_dir, + unique_hangs, describe_op(0)); + +#else + + fn = alloc_printf("%s/hangs/id_%06llu", out_dir, + unique_hangs); + +#endif /* ^!SIMPLE_FILES */ + + ++unique_hangs; + + last_hang_time = get_cur_time(); + + break; + + case FAULT_CRASH: + +keep_as_crash: + + /* This is handled in a manner roughly similar to timeouts, + except for slightly different limits and no need to re-run test + cases. */ + + ++total_crashes; + + if (unique_crashes >= KEEP_UNIQUE_CRASH) return keeping; + + if (!dumb_mode) { + +#ifdef __x86_64__ + simplify_trace((u64*)trace_bits); +#else + simplify_trace((u32*)trace_bits); +#endif /* ^__x86_64__ */ + + if (!has_new_bits(virgin_crash)) return keeping; + + } + + if (!unique_crashes) write_crash_readme(); + +#ifndef SIMPLE_FILES + + fn = alloc_printf("%s/crashes/id:%06llu,sig:%02u,%s", out_dir, + unique_crashes, kill_signal, describe_op(0)); + +#else + + fn = alloc_printf("%s/crashes/id_%06llu_%02u", out_dir, unique_crashes, + kill_signal); + +#endif /* ^!SIMPLE_FILES */ + + ++unique_crashes; + + last_crash_time = get_cur_time(); + last_crash_execs = total_execs; + + break; + + case FAULT_ERROR: FATAL("Unable to execute target application"); + + default: return keeping; + + } + + /* If we're here, we apparently want to save the crash or hang + test case, too. */ + + fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, 0600); + if (fd < 0) PFATAL("Unable to create '%s'", fn); + ck_write(fd, mem, len, fn); + close(fd); + + ck_free(fn); + + return keeping; + +} + |