diff options
Diffstat (limited to 'src/afl-fuzz-run.c')
-rw-r--r-- | src/afl-fuzz-run.c | 120 |
1 files changed, 84 insertions, 36 deletions
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6ad6444a..bf8c4ec0 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -34,7 +34,7 @@ information. The called program will update afl->fsrv->trace_bits. */ fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, - u32 timeout) { + u32 timeout) { fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon); // TODO: Don't classify for faults? @@ -72,9 +72,12 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { size_t new_size = afl->mutator->afl_custom_pre_save(afl->mutator->data, mem, len, &new_buf); - if (unlikely(!new_buf)) + if (unlikely(!new_buf)) { + FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size); + } + /* everything as planned. use the new data. */ afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); @@ -108,27 +111,34 @@ static void write_with_gap(afl_state_t *afl, void *mem, u32 len, u32 skip_at, } - if (fd < 0) PFATAL("Unable to create '%s'", afl->fsrv.out_file); + if (fd < 0) { PFATAL("Unable to create '%s'", afl->fsrv.out_file); } - } else + } else { lseek(fd, 0, SEEK_SET); - if (skip_at) ck_write(fd, mem, skip_at, afl->fsrv.out_file); + } + + if (skip_at) { ck_write(fd, mem, skip_at, afl->fsrv.out_file); } u8 *memu8 = mem; - if (tail_len) + if (tail_len) { + ck_write(fd, memu8 + skip_at + skip_len, tail_len, afl->fsrv.out_file); + } + if (!afl->fsrv.out_file) { - if (ftruncate(fd, len - skip_len)) PFATAL("ftruncate() failed"); + if (ftruncate(fd, len - skip_len)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); - } else + } else { close(fd); + } + } /* Calibrate a new test case. This is done when processing the input directory @@ -151,10 +161,13 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, trying to calibrate already-added finds. This helps avoid trouble due to intermittent latency. */ - if (!from_queue || afl->resuming_fuzz) + if (!from_queue || afl->resuming_fuzz) { + use_tmout = MAX(afl->fsrv.exec_tmout + CAL_TMOUT_ADD, afl->fsrv.exec_tmout * CAL_TMOUT_PERC / 100); + } + ++q->cal_failed; afl->stage_name = "calibration"; @@ -177,18 +190,24 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } - if (q->exec_cksum) + if (q->exec_cksum) { + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); + } + start_us = get_cur_time_us(); for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { u32 cksum; - if (!first_run && !(afl->stage_cur % afl->stats_update_freq)) + if (!first_run && !(afl->stage_cur % afl->stats_update_freq)) { + show_stats(afl); + } + write_to_testcase(afl, use_mem, q->len); fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); @@ -196,7 +215,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, we want to bail out quickly. */ - if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration; + if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; } if (!afl->dumb_mode && !afl->stage_cur && !count_bytes(afl, afl->fsrv.trace_bits)) { @@ -211,7 +230,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (q->exec_cksum != cksum) { u8 hnb = has_new_bits(afl, afl->virgin_bits); - if (hnb > new_bits) new_bits = hnb; + if (hnb > new_bits) { new_bits = hnb; } if (q->exec_cksum) { @@ -220,9 +239,12 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, for (i = 0; i < afl->fsrv.map_size; ++i) { if (unlikely(!afl->var_bytes[i]) && - unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) + unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) { + afl->var_bytes[i] = 1; + } + } var_detected = 1; @@ -261,9 +283,12 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, parent. This is a non-critical problem, but something to warn the user about. */ - if (!afl->dumb_mode && first_run && !fault && !new_bits) + if (!afl->dumb_mode && first_run && !fault && !new_bits) { + fault = FSRV_RUN_NOBITS; + } + abort_calibration: if (new_bits == 2 && !q->has_new_cov) { @@ -292,7 +317,7 @@ abort_calibration: afl->stage_cur = old_sc; afl->stage_max = old_sm; - if (!first_run) show_stats(afl); + if (!first_run) { show_stats(afl); } return fault; @@ -307,7 +332,7 @@ void sync_fuzzers(afl_state_t *afl) { u32 sync_cnt = 0; sd = opendir(afl->sync_dir); - if (!sd) PFATAL("Unable to open '%s'", afl->sync_dir); + if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); } afl->stage_max = afl->stage_cur = 0; afl->cur_depth = 0; @@ -326,9 +351,12 @@ void sync_fuzzers(afl_state_t *afl) { /* Skip dot files and our own output directory. */ - if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) + if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) { + continue; + } + /* Skip anything that doesn't have a queue/ subdirectory. */ qd_path = alloc_printf("%s/%s/queue", afl->sync_dir, sd_ent->d_name); @@ -347,9 +375,13 @@ void sync_fuzzers(afl_state_t *afl) { id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600); - if (id_fd < 0) PFATAL("Unable to create '%s'", qd_synced_path); + if (id_fd < 0) { PFATAL("Unable to create '%s'", qd_synced_path); } - if (read(id_fd, &min_accept, sizeof(u32)) > 0) lseek(id_fd, 0, SEEK_SET); + if (read(id_fd, &min_accept, sizeof(u32)) > 0) { + + lseek(id_fd, 0, SEEK_SET); + + } next_min_accept = min_accept; @@ -372,14 +404,20 @@ void sync_fuzzers(afl_state_t *afl) { if (qd_ent->d_name[0] == '.' || sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &afl->syncing_case) != 1 || - afl->syncing_case < min_accept) + afl->syncing_case < min_accept) { + continue; + } + /* OK, sounds like a new one. Let's give it a try. */ - if (afl->syncing_case >= next_min_accept) + if (afl->syncing_case >= next_min_accept) { + next_min_accept = afl->syncing_case + 1; + } + path = alloc_printf("%s/%s", qd_path, qd_ent->d_name); /* Allow this to fail in case the other fuzzer is resuming or so... */ @@ -393,7 +431,7 @@ void sync_fuzzers(afl_state_t *afl) { } - if (fstat(fd, &st)) PFATAL("fstat() failed"); + if (fstat(fd, &st)) { PFATAL("fstat() failed"); } /* Ignore zero-sized or oversized files. */ @@ -402,7 +440,7 @@ void sync_fuzzers(afl_state_t *afl) { u8 fault; u8 *mem = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (mem == MAP_FAILED) PFATAL("Unable to mmap '%s'", path); + if (mem == MAP_FAILED) { PFATAL("Unable to mmap '%s'", path); } /* See what happens. We rely on save_if_interesting() to catch major errors and save the test case. */ @@ -411,7 +449,7 @@ void sync_fuzzers(afl_state_t *afl) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - if (afl->stop_soon) goto close_sync; + if (afl->stop_soon) { goto close_sync; } afl->syncing_party = sd_ent->d_name; afl->queued_imported += @@ -420,7 +458,7 @@ void sync_fuzzers(afl_state_t *afl) { munmap(mem, st.st_size); - if (!(afl->stage_cur++ % afl->stats_update_freq)) show_stats(afl); + if (!(afl->stage_cur++ % afl->stats_update_freq)) { show_stats(afl); } } @@ -450,9 +488,12 @@ void sync_fuzzers(afl_state_t *afl) { u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Custom mutator trimmer */ - if (afl->mutator && afl->mutator->afl_custom_trim) + if (afl->mutator && afl->mutator->afl_custom_trim) { + return trim_case_custom(afl, q, in_buf); + } + u8 needs_write = 0, fault = 0; u32 trim_exec = 0; u32 remove_len; @@ -464,7 +505,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { detected, it will still work to some extent, so we don't check for this. */ - if (q->len < 5) return 0; + if (q->len < 5) { return 0; } afl->stage_name = afl->stage_name_buf; afl->bytes_trim_in += q->len; @@ -499,7 +540,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); ++afl->trim_execs; - if (afl->stop_soon || fault == FSRV_RUN_ERROR) goto abort_trimming; + if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; } /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ @@ -531,13 +572,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } - } else + } else { remove_pos += remove_len; + } + /* Since this can be slow, update the screen every now and then. */ - if (!(trim_exec++ % afl->stats_update_freq)) show_stats(afl); + if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); } ++afl->stage_cur; } @@ -564,7 +607,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { } - if (fd < 0) PFATAL("Unable to create '%s'", q->fname); + if (fd < 0) { PFATAL("Unable to create '%s'", q->fname); } ck_write(fd, in_buf, q->len, q->fname); close(fd); @@ -595,7 +638,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { size_t post_len = afl->post_handler(afl->post_data, out_buf, len, &post_buf); - if (!post_buf || !post_len) return 0; + if (!post_buf || !post_len) { return 0; } out_buf = post_buf; len = post_len; @@ -605,7 +648,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout); - if (afl->stop_soon) return 1; + if (afl->stop_soon) { return 1; } if (fault == FSRV_RUN_TMOUT) { @@ -616,10 +659,12 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { } - } else + } else { afl->subseq_tmouts = 0; + } + /* Users can hit us with SIGUSR1 to request the current input to be abandoned. */ @@ -636,9 +681,12 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { afl->queued_discovered += save_if_interesting(afl, out_buf, len, fault); if (!(afl->stage_cur % afl->stats_update_freq) || - afl->stage_cur + 1 == afl->stage_max) + afl->stage_cur + 1 == afl->stage_max) { + show_stats(afl); + } + return 0; } |