diff options
author | vanhauser-thc <vh@thc.org> | 2020-09-05 12:32:10 +0200 |
---|---|---|
committer | vanhauser-thc <vh@thc.org> | 2020-09-05 12:32:10 +0200 |
commit | 4b3ad5f037ee9a36aa057bf55a69acca1f573922 (patch) | |
tree | 80887d673817863f3964b5cdb1f8f00347fc6290 /src/afl-fuzz-init.c | |
parent | 996986bed5f2dd97a3d76f584d8eddc1203f8396 (diff) | |
download | afl++-4b3ad5f037ee9a36aa057bf55a69acca1f573922.tar.gz |
add cull queue, -i subdir traversal
Diffstat (limited to 'src/afl-fuzz-init.c')
-rw-r--r-- | src/afl-fuzz-init.c | 108 |
1 files changed, 95 insertions, 13 deletions
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 102f04b9..713849a1 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -611,17 +611,17 @@ void read_foreign_testcases(afl_state_t *afl, int first) { /* Read all testcases from the input directory, then queue them for testing. Called at startup. */ -void read_testcases(afl_state_t *afl) { +void read_testcases(afl_state_t *afl, u8 *directory) { struct dirent **nl; - s32 nl_cnt; + s32 nl_cnt, subdirs = 1; u32 i; - u8 * fn1; - + u8 * fn1, *dir = directory; u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; /* Auto-detect non-in-place resumption attempts. */ +if (dir == NULL) { fn1 = alloc_printf("%s/queue", afl->in_dir); if (!access(fn1, F_OK)) { @@ -632,16 +632,18 @@ void read_testcases(afl_state_t *afl) { ck_free(fn1); } + dir = afl->in_dir; +} - ACTF("Scanning '%s'...", afl->in_dir); + ACTF("Scanning '%s'...", dir); /* We use scandir() + alphasort() rather than readdir() because otherwise, the ordering of test cases would vary somewhat randomly and would be difficult to control. */ - nl_cnt = scandir(afl->in_dir, &nl, NULL, alphasort); + nl_cnt = scandir(dir, &nl, NULL, alphasort); - if (nl_cnt < 0) { + if (nl_cnt < 0 && directory == NULL) { if (errno == ENOENT || errno == ENOTDIR) { @@ -656,7 +658,7 @@ void read_testcases(afl_state_t *afl) { } - PFATAL("Unable to open '%s'", afl->in_dir); + PFATAL("Unable to open '%s'", dir); } @@ -674,19 +676,29 @@ void read_testcases(afl_state_t *afl) { u8 dfn[PATH_MAX]; snprintf(dfn, PATH_MAX, "%s/.state/deterministic_done/%s", afl->in_dir, nl[i]->d_name); - u8 *fn2 = alloc_printf("%s/%s", afl->in_dir, nl[i]->d_name); + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); u8 passed_det = 0; - free(nl[i]); /* not tracked */ - if (lstat(fn2, &st) || access(fn2, R_OK)) { PFATAL("Unable to access '%s'", fn2); } - /* This also takes care of . and .. */ + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + + free(nl[i]); /* not tracked */ + read_testcases(afl, fn2); + ck_free(fn2); + continue; + + } + + free(nl[i]); if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) { @@ -718,7 +730,7 @@ void read_testcases(afl_state_t *afl) { free(nl); /* not tracked */ - if (!afl->queued_paths) { + if (!afl->queued_paths && directory == NULL) { SAYF("\n" cLRD "[-] " cRST "Looks like there are no valid test cases in the input directory! The " @@ -985,6 +997,76 @@ void perform_dry_run(afl_state_t *afl) { } + /* Now we remove all entries from the queue that have a duplicate trace map */ + + q = afl->queue; + struct queue_entry *p, *prev = NULL; + int duplicates = 0; + +restart_outer_cull_loop: + + while (q) { + + if (q->cal_failed || !q->exec_cksum) continue; + + restart_inner_cull_loop: + + p = q->next; + + while (p) { + + if (!p->cal_failed && p->exec_cksum == q->exec_cksum) { + + duplicates = 1; + --afl->pending_not_fuzzed; + + // We do not remove any of the memory allocated because for + // splicing the data might still be interesting. + // We only decouple them from the linked list. + // This will result in some leaks at exit, but who cares. + + // we keep the shorter file + if (p->len >= q->len) { + + q->next = p->next; + goto restart_inner_cull_loop; + + } else { + + if (prev) + prev->next = q = p; + else + afl->queue = q = p; + goto restart_outer_cull_loop; + + } + + } + + p = p->next; + + } + + prev = q; + q = q->next; + + } + + if (duplicates) { + + afl->max_depth = 0; + q = afl->queue; + while (q) { + + if (q->depth > afl->max_depth) afl->max_depth = q->depth; + q = q->next; + + } + + afl->q_prev100 = afl->queue = afl->queue_top = afl->queue; + + } + OKF("All test cases processed."); } |