diff options
Diffstat (limited to 'src/afl-fuzz-init.c')
-rw-r--r-- | src/afl-fuzz-init.c | 321 |
1 files changed, 264 insertions, 57 deletions
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index baf56a5f..7310e49f 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -5,11 +5,11 @@ Originally written by Michal Zalewski Now maintained by Marc Heuse <mh@mh-sec.de>, - Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and + Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and Andrea Fioraldi <andreafioraldi@gmail.com> Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2023 AFLplusplus Project. All rights reserved. + Copyright 2019-2024 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -124,6 +124,9 @@ void bind_to_free_cpu(afl_state_t *afl) { } WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set)."); + #ifdef __linux__ + if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = 0; } + #endif return; } @@ -151,6 +154,9 @@ void bind_to_free_cpu(afl_state_t *afl) { } else { OKF("CPU binding request using -b %d successful.", afl->cpu_to_bind); + #ifdef __linux__ + if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = afl->cpu_to_bind; } + #endif } @@ -453,6 +459,24 @@ void bind_to_free_cpu(afl_state_t *afl) { #endif /* HAVE_AFFINITY */ +/* transforms spaces in a string to underscores (inplace) */ + +static void no_spaces(u8 *string) { + + if (string) { + + u8 *ptr = string; + while (*ptr != 0) { + + if (*ptr == ' ') { *ptr = '_'; } + ++ptr; + + } + + } + +} + /* Shuffle an array of pointers. Might be slightly biased. */ static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) { @@ -553,6 +577,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) { afl->stage_cur = 0; afl->stage_max = 0; + show_stats(afl); + for (i = 0; i < (u32)nl_cnt; ++i) { struct stat st; @@ -631,7 +657,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) { munmap(mem, st.st_size); close(fd); - if (st.st_mtime > mtime_max) mtime_max = st.st_mtime; + if (st.st_mtime > mtime_max) { + + mtime_max = st.st_mtime; + show_stats(afl); + + } } @@ -908,6 +939,14 @@ void perform_dry_run(afl_state_t *afl) { res = calibrate_case(afl, q, use_mem, 0, 1); + /* For AFLFast schedules we update the queue entry */ + if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE) && + likely(q->exec_cksum)) { + + q->n_fuzz_entry = q->exec_cksum % N_FUZZ_SIZE; + + } + if (afl->stop_soon) { return; } if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) { @@ -942,6 +981,7 @@ void perform_dry_run(afl_state_t *afl) { if (!q->was_fuzzed) { q->was_fuzzed = 1; + afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; @@ -951,19 +991,48 @@ void perform_dry_run(afl_state_t *afl) { } else { - SAYF("\n" cLRD "[-] " cRST - "The program took more than %u ms to process one of the initial " - "test cases.\n" - " This is bad news; raising the limit with the -t option is " - "possible, but\n" - " will probably make the fuzzing process extremely slow.\n\n" + static int say_once = 0; + + if (!say_once) { + + SAYF( + "\n" cLRD "[-] " cRST + "The program took more than %u ms to process one of the " + "initial " + "test cases.\n" + " This is bad news; raising the limit with the -t option is " + "possible, but\n" + " will probably make the fuzzing process extremely slow.\n\n" + + " If this test case is just a fluke, the other option is to " + "just avoid it\n" + " altogether, and find one that is less of a CPU hog.\n", + afl->fsrv.exec_tmout); + + if (!afl->afl_env.afl_ignore_seed_problems) { + + FATAL("Test case '%s' results in a timeout", fn); - " If this test case is just a fluke, the other option is to " - "just avoid it\n" - " altogether, and find one that is less of a CPU hog.\n", - afl->fsrv.exec_tmout); + } - FATAL("Test case '%s' results in a timeout", fn); + say_once = 1; + + } + + if (!q->was_fuzzed) { + + q->was_fuzzed = 1; + afl->reinit_table = 1; + --afl->pending_not_fuzzed; + --afl->active_items; + + } + + q->disabled = 1; + q->perf_score = 0; + + WARNF("Test case '%s' results in a timeout, skipping", fn); + break; } @@ -1012,7 +1081,7 @@ void perform_dry_run(afl_state_t *afl) { " - Least likely, there is a horrible bug in the fuzzer. If " "other options\n" - " fail, poke <afl-users@googlegroups.com> for " + " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n", stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), @@ -1041,7 +1110,7 @@ void perform_dry_run(afl_state_t *afl) { " - Least likely, there is a horrible bug in the fuzzer. If " "other options\n" - " fail, poke <afl-users@googlegroups.com> for " + " fail, poke the Awesome Fuzzing Discord for " "troubleshooting tips.\n"); } @@ -1058,7 +1127,19 @@ void perform_dry_run(afl_state_t *afl) { } else { - WARNF("Test case '%s' results in a crash, skipping", fn); + if (afl->afl_env.afl_crashing_seeds_as_new_crash) { + + WARNF( + "Test case '%s' results in a crash, " + "as AFL_CRASHING_SEEDS_AS_NEW_CRASH is set, " + "saving as a new crash", + fn); + + } else { + + WARNF("Test case '%s' results in a crash, skipping", fn); + + } } @@ -1073,41 +1154,118 @@ void perform_dry_run(afl_state_t *afl) { if (!q->was_fuzzed) { q->was_fuzzed = 1; + afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; } - q->disabled = 1; - q->perf_score = 0; + /* Crashing seeds will be regarded as new crashes on startup */ + if (afl->afl_env.afl_crashing_seeds_as_new_crash) { - u32 i = 0; - while (unlikely(i < afl->queued_items && afl->queue_buf[i] && - afl->queue_buf[i]->disabled)) { + ++afl->total_crashes; - ++i; + if (likely(!afl->non_instrumented_mode)) { - } + classify_counts(&afl->fsrv); + + simplify_trace(afl, afl->fsrv.trace_bits); + + if (!has_new_bits(afl, afl->virgin_crash)) { break; } + + } + + if (unlikely(!afl->saved_crashes) && + (afl->afl_env.afl_no_crash_readme != 1)) { - if (i < afl->queued_items && afl->queue_buf[i]) { + write_crash_readme(afl); - afl->queue = afl->queue_buf[i]; + } + + u8 crash_fn[PATH_MAX]; + u8 *use_name = strstr(q->fname, ",orig:"); + + afl->stage_name = "dry_run"; + afl->stage_short = "dry_run"; + +#ifndef SIMPLE_FILES + + if (!afl->afl_env.afl_sha1_filenames) { + + snprintf( + crash_fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s%s%s", + afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal, + describe_op( + afl, 0, + NAME_MAX - strlen("id:000000,sig:00,") - strlen(use_name)), + use_name, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + + } else { + + const char *hex = sha1_hex(use_mem, read_len); + snprintf( + crash_fn, PATH_MAX, "%s/crashes/%s%s%s", afl->out_dir, hex, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + ck_free((char *)hex); + + } + +#else + + snprintf( + crash_fn, PATH_MAX, "%s/crashes/id_%06llu_%02u%s%s", afl->out_dir, + afl->saved_crashes, afl->fsrv.last_kill_signal, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + +#endif + + ++afl->saved_crashes; + + fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_fn); } + ck_write(fd, use_mem, read_len, crash_fn); + close(fd); + + afl->last_crash_time = get_cur_time(); + afl->last_crash_execs = afl->fsrv.total_execs; } else { - afl->queue = afl->queue_buf[0]; + u32 i = 0; + while (unlikely(i < afl->queued_items && afl->queue_buf[i] && + afl->queue_buf[i]->disabled)) { - } + ++i; + + } + + if (i < afl->queued_items && afl->queue_buf[i]) { + + afl->queue = afl->queue_buf[i]; + + } else { + + afl->queue = afl->queue_buf[0]; + + } + + afl->max_depth = 0; + for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) { - afl->max_depth = 0; - for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) { + if (!afl->queue_buf[i]->disabled && + afl->queue_buf[i]->depth > afl->max_depth) + afl->max_depth = afl->queue_buf[i]->depth; - if (!afl->queue_buf[i]->disabled && - afl->queue_buf[i]->depth > afl->max_depth) - afl->max_depth = afl->queue_buf[i]->depth; + } } + q->disabled = 1; + q->perf_score = 0; + break; case FSRV_RUN_ERROR: @@ -1192,6 +1350,7 @@ void perform_dry_run(afl_state_t *afl) { if (!p->was_fuzzed) { p->was_fuzzed = 1; + afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; @@ -1212,6 +1371,7 @@ void perform_dry_run(afl_state_t *afl) { if (!q->was_fuzzed) { q->was_fuzzed = 1; + afl->reinit_table = 1; --afl->pending_not_fuzzed; --afl->active_items; @@ -1262,11 +1422,11 @@ void perform_dry_run(afl_state_t *afl) { static void link_or_copy(u8 *old_path, u8 *new_path) { s32 i = link(old_path, new_path); + if (!i) { return; } + s32 sfd, dfd; u8 *tmp; - if (!i) { return; } - sfd = open(old_path, O_RDONLY); if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); } @@ -1329,7 +1489,9 @@ void pivot_inputs(afl_state_t *afl) { u32 src_id; afl->resuming_fuzz = 1; - nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl); + nfn = alloc_printf( + "%s/queue/%s%s%s", afl->out_dir, rsl, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); /* Since we're at it, let's also get the parent and figure out the appropriate depth for this entry. */ @@ -1369,12 +1531,33 @@ void pivot_inputs(afl_state_t *afl) { } - nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s", - afl->out_dir, id, afl->fsrv.total_execs, use_name); + if (!afl->afl_env.afl_sha1_filenames) { + + nfn = alloc_printf( + "%s/queue/id:%06u,time:0,execs:%llu,orig:%s%s%s", afl->out_dir, id, + afl->fsrv.total_execs, use_name, afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + + } else { + + const char *hex = sha1_hex_for_file(q->fname, q->len); + nfn = alloc_printf( + "%s/queue/%s%s%s", afl->out_dir, hex, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); + ck_free((char *)hex); + + } + + u8 *pos = strrchr(nfn, '/'); + no_spaces(pos + 30); #else - nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id); + nfn = alloc_printf( + "%s/queue/id_%06u%s%s", afl->out_dir, id, + afl->file_extension ? "." : "", + afl->file_extension ? (const char *)afl->file_extension : ""); #endif /* ^!SIMPLE_FILES */ @@ -1542,8 +1725,8 @@ double get_runnable_processes(void) { processes well. */ FILE *f = fopen("/proc/stat", "r"); - u8 tmp[1024]; - u32 val = 0; + u8 tmp[1024]; + u32 val = 0; if (!f) { return 0; } @@ -1581,10 +1764,11 @@ double get_runnable_processes(void) { void nuke_resume_dir(afl_state_t *afl) { - u8 *fn; + u8 *const case_prefix = afl->afl_env.afl_sha1_filenames ? "" : CASE_PREFIX; + u8 *fn; fn = alloc_printf("%s/_resume/.state/deterministic_done", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/_resume/.state/auto_extras", afl->out_dir); @@ -1592,11 +1776,11 @@ void nuke_resume_dir(afl_state_t *afl) { ck_free(fn); fn = alloc_printf("%s/_resume/.state/redundant_edges", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/_resume/.state/variable_behavior", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/_resume/.state", afl->out_dir); @@ -1604,7 +1788,7 @@ void nuke_resume_dir(afl_state_t *afl) { ck_free(fn); fn = alloc_printf("%s/_resume", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); return; @@ -1621,8 +1805,9 @@ dir_cleanup_failed: static void handle_existing_out_dir(afl_state_t *afl) { - FILE *f; - u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); + u8 *const case_prefix = afl->afl_env.afl_sha1_filenames ? "" : CASE_PREFIX; + FILE *f; + u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); /* See if the output directory is locked. If yes, bail out. If not, create a lock that will persist for the lifetime of the process @@ -1744,7 +1929,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { /* Next, we need to clean up <afl->out_dir>/queue/.state/ subdirectories: */ fn = alloc_printf("%s/queue/.state/deterministic_done", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/queue/.state/auto_extras", afl->out_dir); @@ -1752,11 +1937,11 @@ static void handle_existing_out_dir(afl_state_t *afl) { ck_free(fn); fn = alloc_printf("%s/queue/.state/redundant_edges", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/queue/.state/variable_behavior", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); /* Then, get rid of the .state subdirectory itself (should be empty by now) @@ -1767,7 +1952,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { ck_free(fn); fn = alloc_printf("%s/queue", afl->out_dir); - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); /* All right, let's do <afl->out_dir>/crashes/id:* and @@ -1811,7 +1996,10 @@ static void handle_existing_out_dir(afl_state_t *afl) { } - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } +#ifdef AFL_PERSISTENT_RECORD + delete_files(fn, RECORD_PREFIX); +#endif + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/hangs", afl->out_dir); @@ -1843,7 +2031,10 @@ static void handle_existing_out_dir(afl_state_t *afl) { } - if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } +#ifdef AFL_PERSISTENT_RECORD + delete_files(fn, RECORD_PREFIX); +#endif + if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; } ck_free(fn); /* And now, for some finishing touches. */ @@ -2126,6 +2317,21 @@ void setup_dirs_fds(afl_state_t *afl) { fflush(afl->fsrv.plot_file); +#ifdef INTROSPECTION + + tmp = alloc_printf("%s/plot_det_data", afl->out_dir); + + int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION); + if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } + ck_free(tmp); + + afl->fsrv.det_plot_file = fdopen(fd, "w"); + if (!afl->fsrv.det_plot_file) { PFATAL("fdopen() failed"); } + + if (afl->in_place_resume) { fseek(afl->fsrv.det_plot_file, 0, SEEK_END); } + +#endif + /* ignore errors */ } @@ -2199,7 +2405,8 @@ void check_crash_handling(void) { reporting the awful way. */ #if !TARGET_OS_IPHONE - if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return; + if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash\\>'")) + return; SAYF( "\n" cLRD "[-] " cRST @@ -2226,7 +2433,7 @@ void check_crash_handling(void) { *BSD, so we can just let it slide for now. */ s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY); - u8 fchar; + u8 fchar; if (fd < 0) { return; } @@ -2365,7 +2572,7 @@ void check_cpu_governor(afl_state_t *afl) { FATAL("Suboptimal CPU scaling governor"); #elif defined __APPLE__ - u64 min = 0, max = 0; + u64 min = 0, max = 0; size_t mlen = sizeof(min); if (afl->afl_env.afl_skip_cpufreq) return; |