diff options
Diffstat (limited to 'src/afl-fuzz-init.c')
-rw-r--r-- | src/afl-fuzz-init.c | 461 |
1 files changed, 302 insertions, 159 deletions
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 55f7ce53..4dd31ac9 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -42,7 +42,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 cpu_used[4096] = {0}; u32 i; - if (afl->cpu_core_count < 2) return; + if (afl->cpu_core_count < 2) { return; } if (afl->afl_env.afl_no_affinity) { @@ -82,7 +82,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 tmp[MAX_LINE]; u8 has_vmsize = 0; - if (!isdigit(de->d_name[0])) continue; + if (!isdigit(de->d_name[0])) { continue; } snprintf(fn, PATH_MAX, "/proc/%s/status", de->d_name); @@ -94,7 +94,7 @@ void bind_to_free_cpu(afl_state_t *afl) { /* Processes without VmSize are probably kernel tasks. */ - if (!strncmp(tmp, "VmSize:\t", 8)) has_vmsize = 1; + if (!strncmp(tmp, "VmSize:\t", 8)) { has_vmsize = 1; } if (!strncmp(tmp, "Cpus_allowed_list:\t", 19) && !strchr(tmp, '-') && !strchr(tmp, ',') && sscanf(tmp + 19, "%u", &hval) == 1 && @@ -190,8 +190,12 @@ void bind_to_free_cpu(afl_state_t *afl) { try: #ifndef __ANDROID__ - for (i = cpu_start; i < afl->cpu_core_count; i++) - if (!cpu_used[i]) break; + for (i = cpu_start; i < afl->cpu_core_count; i++) { + + if (!cpu_used[i]) { break; } + + } + if (i == afl->cpu_core_count) { #else @@ -229,8 +233,12 @@ void bind_to_free_cpu(afl_state_t *afl) { #if defined(__linux__) if (sched_setaffinity(0, sizeof(c), &c)) { - if (cpu_start == afl->cpu_core_count) + if (cpu_start == afl->cpu_core_count) { + PFATAL("sched_setaffinity failed for CPU %d, exit", i); + + } + WARNF("sched_setaffinity failed to CPU %d, trying next CPU", i); cpu_start++; goto try @@ -282,30 +290,37 @@ void setup_post(afl_state_t *afl) { u32 tlen = 6; strncpy(tbuf, "hello", tlen); - if (!fn) return; + if (!fn) { return; } ACTF("Loading postprocessor from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); - if (!dh) FATAL("%s", dlerror()); + if (!dh) { FATAL("%s", dlerror()); } afl->post_handler = dlsym(dh, "afl_postprocess"); - if (!afl->post_handler) FATAL("Symbol 'afl_postprocess' not found."); + if (!afl->post_handler) { FATAL("Symbol 'afl_postprocess' not found."); } afl->post_init = dlsym(dh, "afl_postprocess_init"); - if (!afl->post_init) FATAL("Symbol 'afl_postprocess_init' not found."); + if (!afl->post_init) { FATAL("Symbol 'afl_postprocess_init' not found."); } afl->post_deinit = dlsym(dh, "afl_postprocess_deinit"); - if (!afl->post_deinit) FATAL("Symbol 'afl_postprocess_deinit' not found."); + if (!afl->post_deinit) { + + FATAL("Symbol 'afl_postprocess_deinit' not found."); + + } /* Do a quick test. It's better to segfault now than later =) */ u8 *post_buf = NULL; afl->post_data = afl->post_init(afl); - if (!afl->post_data) FATAL("Could not initialize post handler."); + if (!afl->post_data) { FATAL("Could not initialize post handler."); } size_t post_len = afl->post_handler(afl->post_data, tbuf, tlen, &post_buf); - if (!post_len || !post_buf) + if (!post_len || !post_buf) { + SAYF("Empty return in test post handler for buf=\"hello\\0\"."); + } + OKF("Postprocessor installed successfully."); } @@ -342,11 +357,16 @@ void read_testcases(afl_state_t *afl) { /* Auto-detect non-in-place resumption attempts. */ fn1 = alloc_printf("%s/queue", afl->in_dir); - if (!access(fn1, F_OK)) + if (!access(fn1, F_OK)) { + afl->in_dir = fn1; - else + + } else { + ck_free(fn1); + } + ACTF("Scanning '%s'...", afl->in_dir); /* We use scandir() + alphasort() rather than readdir() because otherwise, @@ -357,7 +377,7 @@ void read_testcases(afl_state_t *afl) { if (nl_cnt < 0) { - if (errno == ENOENT || errno == ENOTDIR) + if (errno == ENOENT || errno == ENOTDIR) { SAYF("\n" cLRD "[-] " cRST "The input directory does not seem to be valid - try again. The " @@ -368,6 +388,8 @@ void read_testcases(afl_state_t *afl) { "the input\n" " directory.\n"); + } + PFATAL("Unable to open '%s'", afl->in_dir); } @@ -392,9 +414,12 @@ void read_testcases(afl_state_t *afl) { free(nl[i]); /* not tracked */ - if (lstat(fn2, &st) || access(fn2, R_OK)) + if (lstat(fn2, &st) || access(fn2, R_OK)) { + PFATAL("Unable to access '%s'", fn2); + } + /* This also takes care of . and .. */ if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { @@ -404,17 +429,20 @@ void read_testcases(afl_state_t *afl) { } - if (st.st_size > MAX_FILE) + if (st.st_size > MAX_FILE) { + FATAL("Test case '%s' is too big (%s, limit is %s)", fn2, stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + } + /* Check for metadata that indicates that deterministic fuzzing is complete for this entry. We don't want to repeat deterministic fuzzing when resuming aborted scans, because it would be pointless and probably very time-consuming. */ - if (!access(dfn, F_OK)) passed_det = 1; + if (!access(dfn, F_OK)) { passed_det = 1; } add_to_queue(afl, fn2, st.st_size, passed_det); @@ -442,23 +470,6 @@ void read_testcases(afl_state_t *afl) { } -/* Examine map coverage. Called once, for first test case. */ - -static void check_map_coverage(afl_state_t *afl) { - - u32 i; - - if (count_bytes(afl, afl->fsrv.trace_bits) < 100) return; - - for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i) - if (afl->fsrv.trace_bits[i]) return; - - if (afl->fsrv.map_size != MAP_SIZE) return; - - WARNF("Recompile binary with newer version of afl to improve coverage!"); - -} - /* Perform dry run of all test cases to confirm that the app is working as expected. This is done only for the initial inputs, and only once. */ @@ -479,31 +490,35 @@ void perform_dry_run(afl_state_t *afl) { ACTF("Attempting dry run with '%s'...", fn); fd = open(q->fname, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", q->fname); + if (fd < 0) { PFATAL("Unable to open '%s'", q->fname); } use_mem = ck_alloc_nozero(q->len); - if (read(fd, use_mem, q->len) != q->len) + if (read(fd, use_mem, q->len) != q->len) { + FATAL("Short read from '%s'", q->fname); + } + close(fd); res = calibrate_case(afl, q, use_mem, 0, 1); ck_free(use_mem); - if (afl->stop_soon) return; + if (afl->stop_soon) { return; } + + if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) { - if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) SAYF(cGRA " len = %u, map size = %u, exec speed = %llu us\n" cRST, q->len, q->bitmap_size, q->exec_us); + } + switch (res) { case FSRV_RUN_OK: - if (q == afl->queue) check_map_coverage(afl); - - if (afl->crash_mode) FATAL("Test case '%s' does *NOT* crash", fn); + if (afl->crash_mode) { FATAL("Test case '%s' does *NOT* crash", fn); } break; @@ -558,7 +573,7 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_CRASH: - if (afl->crash_mode) break; + if (afl->crash_mode) { break; } if (skip_crashes) { @@ -654,20 +669,28 @@ void perform_dry_run(afl_state_t *afl) { FATAL("Unable to execute target application ('%s')", afl->argv[0]); - case FSRV_RUN_NOINST: FATAL("No instrumentation detected"); + case FSRV_RUN_NOINST: + FATAL("No instrumentation detected"); case FSRV_RUN_NOBITS: ++afl->useless_at_start; - if (!afl->in_bitmap && !afl->shuffle_queue) + if (!afl->in_bitmap && !afl->shuffle_queue) { + WARNF("No new instrumentation output, test case may be useless."); + } + break; } - if (q->var_behavior) WARNF("Instrumentation output varies across runs."); + if (q->var_behavior) { + + WARNF("Instrumentation output varies across runs."); + + } q = q->next; @@ -675,17 +698,23 @@ void perform_dry_run(afl_state_t *afl) { if (cal_failures) { - if (cal_failures == afl->queued_paths) + if (cal_failures == afl->queued_paths) { + FATAL("All test cases time out%s, giving up!", skip_crashes ? " or crash" : ""); + } + WARNF("Skipped %u test cases (%0.02f%%) due to timeouts%s.", cal_failures, ((double)cal_failures) * 100 / afl->queued_paths, skip_crashes ? " or crashes" : ""); - if (cal_failures * 5 > afl->queued_paths) + if (cal_failures * 5 > afl->queued_paths) { + WARNF(cLRD "High percentage of rejected test cases, check settings!"); + } + } OKF("All test cases processed."); @@ -700,20 +729,23 @@ static void link_or_copy(u8 *old_path, u8 *new_path) { s32 sfd, dfd; u8 *tmp; - if (!i) return; + if (!i) { return; } sfd = open(old_path, O_RDONLY); - if (sfd < 0) PFATAL("Unable to open '%s'", old_path); + if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); } dfd = open(new_path, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (dfd < 0) PFATAL("Unable to create '%s'", new_path); + if (dfd < 0) { PFATAL("Unable to create '%s'", new_path); } tmp = ck_alloc(64 * 1024); - while ((i = read(sfd, tmp, 64 * 1024)) > 0) + while ((i = read(sfd, tmp, 64 * 1024)) > 0) { + ck_write(dfd, tmp, i, new_path); - if (i < 0) PFATAL("read() failed"); + } + + if (i < 0) { PFATAL("read() failed"); } ck_free(tmp); close(sfd); @@ -736,11 +768,16 @@ void pivot_inputs(afl_state_t *afl) { u8 *nfn, *rsl = strrchr(q->fname, '/'); u32 orig_id; - if (!rsl) + if (!rsl) { + rsl = q->fname; - else + + } else { + ++rsl; + } + /* If the original file name conforms to the syntax and the recorded ID matches the one we'd assign, just use the original file name. This is valuable for resuming fuzzing runs. */ @@ -762,11 +799,15 @@ void pivot_inputs(afl_state_t *afl) { if (src_str && sscanf(src_str + 1, "%06u", &src_id) == 1) { struct queue_entry *s = afl->queue; - while (src_id-- && s) + while (src_id-- && s) { + s = s->next; - if (s) q->depth = s->depth + 1; - if (afl->max_depth < q->depth) afl->max_depth = q->depth; + } + + if (s) { q->depth = s->depth + 1; } + + if (afl->max_depth < q->depth) { afl->max_depth = q->depth; } } @@ -779,10 +820,16 @@ void pivot_inputs(afl_state_t *afl) { u8 *use_name = strstr(rsl, ",orig:"); - if (use_name) + if (use_name) { + use_name += 6; - else + + } else { + use_name = rsl; + + } + nfn = alloc_printf("%s/queue/id:%06u,time:0,orig:%s", afl->out_dir, id, use_name); @@ -802,14 +849,14 @@ void pivot_inputs(afl_state_t *afl) { /* Make sure that the passed_det value carries over, too. */ - if (q->passed_det) mark_as_det_done(afl, q); + if (q->passed_det) { mark_as_det_done(afl, q); } q = q->next; ++id; } - if (afl->in_place_resume) nuke_resume_dir(afl); + if (afl->in_place_resume) { nuke_resume_dir(afl); } } @@ -824,27 +871,32 @@ u32 find_start_position(afl_state_t *afl) { s32 fd, i; u32 ret; - if (!afl->resuming_fuzz) return 0; + if (!afl->resuming_fuzz) { return 0; } + + if (afl->in_place_resume) { - if (afl->in_place_resume) fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); - else + + } else { + fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir); + } + fd = open(fn, O_RDONLY); ck_free(fn); - if (fd < 0) return 0; + if (fd < 0) { return 0; } i = read(fd, tmp, sizeof(tmp) - 1); (void)i; /* Ignore errors */ close(fd); off = strstr(tmp, "cur_path : "); - if (!off) return 0; + if (!off) { return 0; } ret = atoi(off + 20); - if (ret >= afl->queued_paths) ret = 0; + if (ret >= afl->queued_paths) { ret = 0; } return ret; } @@ -861,27 +913,32 @@ void find_timeout(afl_state_t *afl) { s32 fd, i; u32 ret; - if (!afl->resuming_fuzz) return; + if (!afl->resuming_fuzz) { return; } + + if (afl->in_place_resume) { - if (afl->in_place_resume) fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); - else + + } else { + fn = alloc_printf("%s/../fuzzer_stats", afl->in_dir); + } + fd = open(fn, O_RDONLY); ck_free(fn); - if (fd < 0) return; + if (fd < 0) { return; } i = read(fd, tmp, sizeof(tmp) - 1); (void)i; /* Ignore errors */ close(fd); off = strstr(tmp, "exec_timeout : "); - if (!off) return; + if (!off) { return; } ret = atoi(off + 20); - if (ret <= 4) return; + if (ret <= 4) { return; } afl->fsrv.exec_tmout = ret; afl->timeout_given = 3; @@ -898,7 +955,7 @@ static u8 delete_files(u8 *path, u8 *prefix) { d = opendir(path); - if (!d) return 0; + if (!d) { return 0; } while ((d_ent = readdir(d))) { @@ -906,7 +963,7 @@ static u8 delete_files(u8 *path, u8 *prefix) { (!prefix || !strncmp(d_ent->d_name, prefix, strlen(prefix)))) { u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name); - if (unlink(fname)) PFATAL("Unable to delete '%s'", fname); + if (unlink(fname)) { PFATAL("Unable to delete '%s'", fname); } ck_free(fname); } @@ -944,14 +1001,17 @@ double get_runnable_processes(void) { u8 tmp[1024]; u32 val = 0; - if (!f) return 0; + if (!f) { return 0; } while (fgets(tmp, sizeof(tmp), f)) { if (!strncmp(tmp, "procs_running ", 14) || - !strncmp(tmp, "procs_blocked ", 14)) + !strncmp(tmp, "procs_blocked ", 14)) { + val += atoi(tmp + 14); + } + } fclose(f); @@ -980,27 +1040,27 @@ void nuke_resume_dir(afl_state_t *afl) { 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); - if (delete_files(fn, "auto_")) goto dir_cleanup_failed; + if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; } 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); - if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; } 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; @@ -1025,7 +1085,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { (this requires leaving the descriptor open).*/ afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY); - if (afl->fsrv.out_dir_fd < 0) PFATAL("Unable to open '%s'", afl->out_dir); + if (afl->fsrv.out_dir_fd < 0) { PFATAL("Unable to open '%s'", afl->out_dir); } #ifndef __sun @@ -1053,9 +1113,12 @@ static void handle_existing_out_dir(afl_state_t *afl) { if (fscanf(f, "start_time : %llu\n" "last_update : %llu\n", - &start_time2, &last_update) != 2) + &start_time2, &last_update) != 2) { + FATAL("Malformed data in '%s'", fn); + } + fclose(f); /* Autoresume treats a normal run as in_place_resume if a valid out dir @@ -1129,7 +1192,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { if (!afl->in_place_resume) { fn = alloc_printf("%s/.synced", afl->out_dir); - if (delete_files(fn, NULL)) goto dir_cleanup_failed; + if (delete_files(fn, NULL)) { goto dir_cleanup_failed; } ck_free(fn); } @@ -1137,30 +1200,30 @@ 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); - if (delete_files(fn, "auto_")) goto dir_cleanup_failed; + if (delete_files(fn, "auto_")) { goto dir_cleanup_failed; } 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) and everything matching <afl->out_dir>/queue/id:*. */ fn = alloc_printf("%s/queue/.state", afl->out_dir); - if (rmdir(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (rmdir(fn) && errno != ENOENT) { goto dir_cleanup_failed; } 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 @@ -1203,7 +1266,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { } - 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/hangs", afl->out_dir); @@ -1234,7 +1297,7 @@ static void handle_existing_out_dir(afl_state_t *afl) { } - if (delete_files(fn, CASE_PREFIX)) goto dir_cleanup_failed; + if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; } ck_free(fn); /* And now, for some finishing touches. */ @@ -1249,27 +1312,27 @@ static void handle_existing_out_dir(afl_state_t *afl) { } - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); if (!afl->in_place_resume) { fn = alloc_printf("%s/fuzzer_stats", afl->out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); } fn = alloc_printf("%s/plot_data", afl->out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); fn = alloc_printf("%s/cmdline", afl->out_dir); - if (unlink(fn) && errno != ENOENT) goto dir_cleanup_failed; + if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; } ck_free(fn); OKF("Output dir cleanup successful."); @@ -1306,28 +1369,37 @@ void setup_dirs_fds(afl_state_t *afl) { ACTF("Setting up output directories..."); - if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) + if (afl->sync_id && mkdir(afl->sync_dir, 0700) && errno != EEXIST) { + PFATAL("Unable to create '%s'", afl->sync_dir); + } + if (mkdir(afl->out_dir, 0700)) { - if (errno != EEXIST) PFATAL("Unable to create '%s'", afl->out_dir); + if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); } handle_existing_out_dir(afl); } else { - if (afl->in_place_resume) + if (afl->in_place_resume) { + FATAL("Resume attempted but old output directory not found"); + } + afl->fsrv.out_dir_fd = open(afl->out_dir, O_RDONLY); #ifndef __sun if (afl->fsrv.out_dir_fd < 0 || - flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB)) + flock(afl->fsrv.out_dir_fd, LOCK_EX | LOCK_NB)) { + PFATAL("Unable to flock() output directory."); + } + #endif /* !__sun */ } @@ -1335,39 +1407,39 @@ void setup_dirs_fds(afl_state_t *afl) { /* Queue directory for any starting & discovered paths. */ tmp = alloc_printf("%s/queue", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Top-level directory for queue metadata used for session resume and related tasks. */ tmp = alloc_printf("%s/queue/.state/", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Directory for flagging queue entries that went through deterministic fuzzing in the past. */ tmp = alloc_printf("%s/queue/.state/deterministic_done/", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Directory with the auto-selected dictionary entries. */ tmp = alloc_printf("%s/queue/.state/auto_extras/", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* The set of paths currently deemed redundant. */ tmp = alloc_printf("%s/queue/.state/redundant_edges/", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* The set of paths showing variable behavior. */ tmp = alloc_printf("%s/queue/.state/variable_behavior/", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Sync directory for keeping track of cooperating fuzzers. */ @@ -1376,9 +1448,12 @@ void setup_dirs_fds(afl_state_t *afl) { tmp = alloc_printf("%s/.synced/", afl->out_dir); - if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) + if (mkdir(tmp, 0700) && (!afl->in_place_resume || errno != EEXIST)) { + PFATAL("Unable to create '%s'", tmp); + } + ck_free(tmp); } @@ -1386,39 +1461,41 @@ void setup_dirs_fds(afl_state_t *afl) { /* All recorded crashes. */ tmp = alloc_printf("%s/crashes", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* All recorded hangs. */ tmp = alloc_printf("%s/hangs", afl->out_dir); - if (mkdir(tmp, 0700)) PFATAL("Unable to create '%s'", tmp); + if (mkdir(tmp, 0700)) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); /* Generally useful file descriptors. */ afl->fsrv.dev_null_fd = open("/dev/null", O_RDWR); - if (afl->fsrv.dev_null_fd < 0) PFATAL("Unable to open /dev/null"); + if (afl->fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } #ifndef HAVE_ARC4RANDOM afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY); - if (afl->fsrv.dev_urandom_fd < 0) PFATAL("Unable to open /dev/urandom"); + if (afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); } #endif /* Gnuplot output file. */ tmp = alloc_printf("%s/plot_data", afl->out_dir); fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", tmp); + if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); afl->fsrv.plot_file = fdopen(fd, "w"); - if (!afl->fsrv.plot_file) PFATAL("fdopen() failed"); + if (!afl->fsrv.plot_file) { PFATAL("fdopen() failed"); } fprintf(afl->fsrv.plot_file, "# unix_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " "unique_hangs, max_depth, execs_per_sec\n"); + fflush(afl->fsrv.plot_file); + /* ignore errors */ } @@ -1434,11 +1511,11 @@ void setup_cmdline_file(afl_state_t *afl, char **argv) { /* Store the command line to reproduce our findings */ tmp = alloc_printf("%s/cmdline", afl->out_dir); fd = open(tmp, O_WRONLY | O_CREAT | O_EXCL, 0600); - if (fd < 0) PFATAL("Unable to create '%s'", tmp); + if (fd < 0) { PFATAL("Unable to create '%s'", tmp); } ck_free(tmp); cmdline_file = fdopen(fd, "w"); - if (!cmdline_file) PFATAL("fdopen() failed"); + if (!cmdline_file) { PFATAL("fdopen() failed"); } while (argv[i]) { @@ -1470,7 +1547,7 @@ void setup_stdio_file(afl_state_t *afl) { afl->fsrv.out_fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0600); - if (afl->fsrv.out_fd < 0) PFATAL("Unable to create '%s'", fn); + if (afl->fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fn); } ck_free(fn); @@ -1518,7 +1595,7 @@ void check_crash_handling(void) { s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY); u8 fchar; - if (fd < 0) return; + if (fd < 0) { return; } ACTF("Checking core_pattern..."); @@ -1541,9 +1618,12 @@ void check_crash_handling(void) { " echo core >/proc/sys/kernel/core_pattern\n"); - if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) + if (!getenv("AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES")) { + FATAL("Pipe at the beginning of 'core_pattern'"); + } + } close(fd); @@ -1561,24 +1641,36 @@ void check_cpu_governor(afl_state_t *afl) { u8 tmp[128]; u64 min = 0, max = 0; - if (afl->afl_env.afl_skip_cpufreq) return; + if (afl->afl_env.afl_skip_cpufreq) { return; } + + if (afl->cpu_aff > 0) { - if (afl->cpu_aff > 0) snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpu", afl->cpu_aff, "/cpufreq/scaling_governor"); - else + + } else { + snprintf(tmp, sizeof(tmp), "%s", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"); + + } + f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor", "r"); if (!f) { - if (afl->cpu_aff > 0) + if (afl->cpu_aff > 0) { + snprintf(tmp, sizeof(tmp), "%s%d%s", "/sys/devices/system/cpu/cpufreq/policy", afl->cpu_aff, "/scaling_governor"); - else + + } else { + snprintf(tmp, sizeof(tmp), "%s", "/sys/devices/system/cpu/cpufreq/policy0/scaling_governor"); + + } + f = fopen(tmp, "r"); } @@ -1592,17 +1684,17 @@ void check_cpu_governor(afl_state_t *afl) { ACTF("Checking CPU scaling governor..."); - if (!fgets(tmp, 128, f)) PFATAL("fgets() failed"); + if (!fgets(tmp, 128, f)) { PFATAL("fgets() failed"); } fclose(f); - if (!strncmp(tmp, "perf", 4)) return; + if (!strncmp(tmp, "perf", 4)) { return; } f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq", "r"); if (f) { - if (fscanf(f, "%llu", &min) != 1) min = 0; + if (fscanf(f, "%llu", &min) != 1) { min = 0; } fclose(f); } @@ -1611,12 +1703,12 @@ void check_cpu_governor(afl_state_t *afl) { if (f) { - if (fscanf(f, "%llu", &max) != 1) max = 0; + if (fscanf(f, "%llu", &max) != 1) { max = 0; } fclose(f); } - if (min == max) return; + if (min == max) { return; } SAYF("\n" cLRD "[-] " cRST "Whoops, your system uses on-demand CPU frequency scaling, adjusted\n" @@ -1769,11 +1861,11 @@ void fix_up_sync(afl_state_t *afl) { u8 *x = afl->sync_id; - if (afl->dumb_mode) FATAL("-S / -M and -n are mutually exclusive"); + if (afl->dumb_mode) { FATAL("-S / -M and -n are mutually exclusive"); } if (afl->skip_deterministic) { - if (afl->force_deterministic) FATAL("use -S instead of -M -d"); + if (afl->force_deterministic) { FATAL("use -S instead of -M -d"); } // else // FATAL("-S already implies -d"); @@ -1781,14 +1873,17 @@ void fix_up_sync(afl_state_t *afl) { while (*x) { - if (!isalnum(*x) && *x != '_' && *x != '-') + if (!isalnum(*x) && *x != '_' && *x != '-') { + FATAL("Non-alphanumeric fuzzer ID specified via -S or -M"); + } + ++x; } - if (strlen(afl->sync_id) > 32) FATAL("Fuzzer ID too long"); + if (strlen(afl->sync_id) > 32) { FATAL("Fuzzer ID too long"); } x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id); @@ -1820,25 +1915,37 @@ void check_asan_opts(void) { if (x) { - if (!strstr(x, "abort_on_error=1")) + if (!strstr(x, "abort_on_error=1")) { + FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!"); - if (!strstr(x, "symbolize=0")) + } + + if (!strstr(x, "symbolize=0")) { + FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!"); + } + } x = get_afl_env("MSAN_OPTIONS"); if (x) { - if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) + if (!strstr(x, "exit_code=" STRINGIFY(MSAN_ERROR))) { + FATAL("Custom MSAN_OPTIONS set without exit_code=" STRINGIFY( MSAN_ERROR) " - please fix!"); - if (!strstr(x, "symbolize=0")) + } + + if (!strstr(x, "symbolize=0")) { + FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!"); + } + } } @@ -1885,9 +1992,12 @@ void check_binary(afl_state_t *afl, u8 *fname) { afl->fsrv.target_path = ck_strdup(fname); if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) || - !(st.st_mode & 0111) || (f_len = st.st_size) < 4) + !(st.st_mode & 0111) || (f_len = st.st_size) < 4) { + FATAL("Program '%s' not found or not executable", fname); + } + } else { while (env_path) { @@ -1900,52 +2010,71 @@ void check_binary(afl_state_t *afl, u8 *fname) { memcpy(cur_elem, env_path, delim - env_path); ++delim; - } else + } else { cur_elem = ck_strdup(env_path); + } + env_path = delim; - if (cur_elem[0]) + if (cur_elem[0]) { + afl->fsrv.target_path = alloc_printf("%s/%s", cur_elem, fname); - else + + } else { + afl->fsrv.target_path = ck_strdup(fname); + } + ck_free(cur_elem); if (!stat(afl->fsrv.target_path, &st) && S_ISREG(st.st_mode) && - (st.st_mode & 0111) && (f_len = st.st_size) >= 4) + (st.st_mode & 0111) && (f_len = st.st_size) >= 4) { + break; + } + ck_free(afl->fsrv.target_path); afl->fsrv.target_path = 0; } - if (!afl->fsrv.target_path) + if (!afl->fsrv.target_path) { + FATAL("Program '%s' not found or not executable", fname); + } + } - if (afl->afl_env.afl_skip_bin_check || afl->use_wine) return; + if (afl->afl_env.afl_skip_bin_check || afl->use_wine) { return; } /* Check for blatant user errors. */ if ((!strncmp(afl->fsrv.target_path, "/tmp/", 5) && !strchr(afl->fsrv.target_path + 5, '/')) || (!strncmp(afl->fsrv.target_path, "/var/tmp/", 9) && - !strchr(afl->fsrv.target_path + 9, '/'))) + !strchr(afl->fsrv.target_path + 9, '/'))) { + FATAL("Please don't keep binaries in /tmp or /var/tmp"); + } + fd = open(afl->fsrv.target_path, O_RDONLY); - if (fd < 0) PFATAL("Unable to open '%s'", afl->fsrv.target_path); + if (fd < 0) { PFATAL("Unable to open '%s'", afl->fsrv.target_path); } f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0); - if (f_data == MAP_FAILED) + if (f_data == MAP_FAILED) { + PFATAL("Unable to mmap file '%s'", afl->fsrv.target_path); + } + close(fd); if (f_data[0] == '#' && f_data[1] == '!') { @@ -1972,9 +2101,12 @@ void check_binary(afl_state_t *afl, u8 *fname) { #ifndef __APPLE__ - if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) + if (f_data[0] != 0x7f || memcmp(f_data + 1, "ELF", 3)) { + FATAL("Program '%s' is not an ELF binary", afl->fsrv.target_path); + } + #else #if !defined(__arm__) && !defined(__arm64__) @@ -2028,9 +2160,12 @@ void check_binary(afl_state_t *afl, u8 *fname) { } if (memmem(f_data, f_len, "__asan_init", 11) || - memmem(f_data, f_len, "__msan_init", 11)) + memmem(f_data, f_len, "__msan_init", 11)) { + afl->fsrv.uses_asan = 1; + } + /* Detect persistent & deferred init signatures in the binary. */ if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) { @@ -2057,7 +2192,7 @@ void check_binary(afl_state_t *afl, u8 *fname) { } - if (munmap(f_data, f_len)) PFATAL("unmap() failed"); + if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); } } @@ -2074,11 +2209,16 @@ void fix_up_banner(afl_state_t *afl, u8 *name) { } else { u8 *trim = strrchr(name, '/'); - if (!trim) + if (!trim) { + afl->use_banner = name; - else + + } else { + afl->use_banner = trim + 1; + } + } } @@ -2169,21 +2309,24 @@ void save_cmdline(afl_state_t *afl, u32 argc, char **argv) { u32 len = 1, i; u8 *buf; - for (i = 0; i < argc; ++i) + for (i = 0; i < argc; ++i) { + len += strlen(argv[i]) + 1; + } + buf = afl->orig_cmdline = ck_alloc(len); for (i = 0; i < argc; ++i) { u32 l = strlen(argv[i]); - if (!argv[i] || !buf) FATAL("null deref detected"); + if (!argv[i] || !buf) { FATAL("null deref detected"); } memcpy(buf, argv[i], l); buf += l; - if (i != argc - 1) *(buf++) = ' '; + if (i != argc - 1) { *(buf++) = ' '; } } |