afl-cmin/afl-cmin.bash/afl-showmap -i descend into subdirectories
MODIFY
docs/Changelog.md
docs/Changelog.md
@@ -31,6 +31,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- afl_analyze:
- fix timeout handling
- add forkserver support for better performance
+ - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into
+ subdirectories (like afl-fuzz does)
- ensure afl-compiler-rt is built for gcc_module
### Version ++3.13c (release)

MODIFY
src/afl-showmap.c
src/afl-showmap.c
@@ -67,6 +67,8 @@ static char *stdin_file; /* stdin file */
static u8 *in_dir = NULL, /* input folder */
*out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
+static u8 outfile[PATH_MAX];
+
static u8 *in_data, /* Input data */
*coverage_map; /* Coverage map */
@@ -88,7 +90,8 @@ static bool quiet_mode, /* Hide non-essential messages? */
have_coverage, /* have coverage? */
no_classify, /* do not classify counts */
debug, /* debug mode */
- print_filenames; /* print the current filename */
+ print_filenames, /* print the current filename */
+ wait_for_gdb;
static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_crashed; /* Child crashed? */
@@ -692,6 +695,93 @@ static void setup_signal_handlers(void) {
}
+u32 execute_testcases(u8 *dir) {
+
+ struct dirent **nl;
+ s32 nl_cnt, subdirs = 1;
+ u32 i, done = 0;
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+
+ if (!be_quiet) { 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(dir, &nl, NULL, alphasort);
+
+ if (nl_cnt < 0) { return 0; }
+
+ for (i = 0; i < (u32)nl_cnt; ++i) {
+
+ struct stat st;
+
+ u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name);
+
+ if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+ PFATAL("Unable to access '%s'", fn2);
+
+ }
+
+ /* 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 */
+ done += execute_testcases(fn2);
+ ck_free(fn2);
+ continue;
+
+ }
+
+ free(nl[i]);
+
+ if (!S_ISREG(st.st_mode) || !st.st_size) {
+
+ ck_free(fn2);
+ continue;
+
+ }
+
+ if (st.st_size > MAX_FILE && !be_quiet) {
+
+ WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", 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));
+
+ }
+
+ // DO
+ if (read_file(fn2)) {
+
+ if (wait_for_gdb) {
+
+ fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
+ fprintf(stderr, "exec: kill -CONT %d\n", getpid());
+ kill(0, SIGSTOP);
+
+ }
+
+ showmap_run_target_forkserver(fsrv, in_data, in_len);
+ ck_free(in_data);
+ ++done;
+
+ if (collect_coverage)
+ analyze_results(fsrv);
+ else
+ tcnt = write_results_to_file(fsrv, outfile);
+
+ }
+
+ }
+
+ free(nl); /* not tracked */
+ return done;
+
+}
+
/* Show banner. */
static void show_banner(void) {
@@ -1137,14 +1227,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (in_dir) {
DIR *dir_in, *dir_out = NULL;
- struct dirent **file_list;
-
- // int done = 0;
- u8 infile[PATH_MAX], outfile[PATH_MAX];
- u8 wait_for_gdb = 0;
-#if !defined(DT_REG)
- struct stat statbuf;
-#endif
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
@@ -1245,65 +1327,12 @@ int main(int argc, char **argv_orig, char **envp) {
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
- int file_count = scandir(in_dir, &file_list, NULL, alphasort);
- if (file_count < 0) {
+ if (execute_testcases(in_dir) == 0) {
- PFATAL("Failed to read from input dir at %s\n", in_dir);
+ FATAL("could not read input testcases from %s", in_dir);
}
- for (int i = 0; i < file_count; i++) {
-
- struct dirent *dir_ent = file_list[i];
-
- if (dir_ent->d_name[0] == '.') {
-
- continue; // skip anything that starts with '.'
-
- }
-
-#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */
- if (dir_ent->d_type != DT_REG) {
-
- continue; // only regular files
-
- }
-
-#endif
-
- snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name);
-
-#if !defined(DT_REG) /* use stat() */
- if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
-#endif
-
- if (!collect_coverage)
- snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
-
- if (read_file(infile)) {
-
- if (wait_for_gdb) {
-
- fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
- fprintf(stderr, "exec: kill -CONT %d\n", getpid());
- kill(0, SIGSTOP);
-
- }
-
- showmap_run_target_forkserver(fsrv, in_data, in_len);
- ck_free(in_data);
- if (collect_coverage)
- analyze_results(fsrv);
- else
- tcnt = write_results_to_file(fsrv, outfile);
-
- }
-
- }
-
- free(file_list);
- file_list = NULL;
-
if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); }
if (dir_out) { closedir(dir_out); }

afl-cmin/afl-cmin.bash/afl-showmap -i descend into subdirectories