aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Maier <domenukk@gmail.com>2020-04-14 19:27:25 +0200
committerDominik Maier <domenukk@gmail.com>2020-04-14 19:27:25 +0200
commit6dc36f1e6e7d2d781cc6b14f2898b3f7021e1d06 (patch)
tree1f46a247e84b0733935565b1513b6f2bdd4d797b
parentf4436f118c7a828e37926b948e997d1c8f5b2b03 (diff)
downloadafl++-6dc36f1e6e7d2d781cc6b14f2898b3f7021e1d06.tar.gz
unified forkservered run_target, fixes #308
-rw-r--r--include/afl-fuzz.h16
-rw-r--r--include/forkserver.h21
-rw-r--r--src/afl-analyze.c2
-rw-r--r--src/afl-forkserver.c132
-rw-r--r--src/afl-fuzz-bitmap.c16
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-init.c14
-rw-r--r--src/afl-fuzz-mutators.c2
-rw-r--r--src/afl-fuzz-one.c12
-rw-r--r--src/afl-fuzz-queue.c2
-rw-r--r--src/afl-fuzz-redqueen.c4
-rw-r--r--src/afl-fuzz-run.c128
-rw-r--r--src/afl-fuzz-stats.c18
-rw-r--r--src/afl-fuzz.c2
-rw-r--r--src/afl-sharedmem.c1
-rw-r--r--src/afl-showmap.c95
-rw-r--r--src/afl-tmin.c109
17 files changed, 222 insertions, 354 deletions
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 3df99a58..abaa71b5 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -195,18 +195,6 @@ enum {
};
-/* Execution status fault codes */
-
-enum {
-
- /* 00 */ FAULT_NONE,
- /* 01 */ FAULT_TMOUT,
- /* 02 */ FAULT_CRASH,
- /* 03 */ FAULT_ERROR,
- /* 04 */ FAULT_NOINST,
- /* 05 */ FAULT_NOBITS
-
-};
#define operator_num 16
#define swarm_num 5
@@ -433,7 +421,6 @@ typedef struct afl_state {
use_splicing, /* Recombine input files? */
dumb_mode, /* Run in non-instrumented mode? */
score_changed, /* Scoring for favorites changed? */
- kill_signal, /* Signal that killed the child */
resuming_fuzz, /* Resuming an older fuzzing job? */
timeout_given, /* Specific timeout given? */
not_on_tty, /* stdout is not a tty */
@@ -488,7 +475,6 @@ typedef struct afl_state {
total_tmouts, /* Total number of timeouts */
unique_tmouts, /* Timeouts with unique signatures */
unique_hangs, /* Hangs with unique signatures */
- total_execs, /* Total execve() calls */
last_crash_execs, /* Exec counter at last crash */
queue_cycle, /* Queue round counter */
cycles_wo_finds, /* Cycles without any new paths */
@@ -888,7 +874,7 @@ void show_init_stats(afl_state_t *);
/* Run */
-u8 run_target(afl_state_t *, afl_forkserver_t *fsrv, u32);
+fsrv_run_result_t run_target(afl_state_t *, afl_forkserver_t *fsrv, u32);
void write_to_testcase(afl_state_t *, void *, u32);
u8 calibrate_case(afl_state_t *, struct queue_entry *, u8 *, u32, u8);
void sync_fuzzers(afl_state_t *);
diff --git a/include/forkserver.h b/include/forkserver.h
index 6fbaf612..7559e785 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -29,6 +29,7 @@
#define __AFL_FORKSERVER_H
#include <stdio.h>
+#include <stdbool.h>
typedef struct afl_forkserver {
@@ -55,16 +56,18 @@ typedef struct afl_forkserver {
u32 snapshot; /* is snapshot feature used */
u64 mem_limit; /* Memory cap for child (MB) */
+ u64 total_execs; /* How often run_target was called */
+
u8 *out_file, /* File to fuzz, if any */
*target_path; /* Path of the target */
FILE *plot_file; /* Gnuplot output file */
- u8 child_timed_out; /* Traced process timed out? */
+ u8 last_run_timed_out; /* Traced process timed out? */
- u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
+ u8 last_kill_signal; /* Signal that killed the child */
- u32 prev_timed_out; /* if prev forkserver run timed out */
+ u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */
u8 qemu_mode; /* if running in qemu mode or not */
@@ -79,10 +82,22 @@ typedef struct afl_forkserver {
} afl_forkserver_t;
+typedef enum fsrv_run_result {
+
+ /* 00 */ FSRV_RUN_OK = 0,
+ /* 01 */ FSRV_RUN_TMOUT,
+ /* 02 */ FSRV_RUN_CRASH,
+ /* 03 */ FSRV_RUN_ERROR,
+ /* 04 */ FSRV_RUN_NOINST,
+ /* 05 */ FSRV_RUN_NOBITS,
+
+} fsrv_run_result_t;
+
void afl_fsrv_init(afl_forkserver_t *fsrv);
void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from);
void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output);
+fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, volatile u8 *stop_soon_p);
void afl_fsrv_killall(void);
void afl_fsrv_deinit(afl_forkserver_t *fsrv);
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 952786b0..8625cfda 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -80,7 +80,7 @@ static u8 edges_only, /* Ignore hit counts? */
use_stdin = 1; /* Use stdin for program input? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
- child_timed_out; /* Child timed out? */
+ child_timed_out; /* Child timed out? */
static u8 *target_path;
static u8 qemu_mode;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index f647ff5d..a7be8e8b 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -76,7 +76,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->child_pid = -1;
fsrv->map_size = MAP_SIZE;
fsrv->use_fauxsrv = 0;
- fsrv->prev_timed_out = 0;
+ fsrv->last_run_timed_out = 0;
fsrv->init_child_func = fsrv_exec_child;
@@ -102,7 +102,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->out_dir_fd = -1;
fsrv_to->child_pid = -1;
fsrv_to->use_fauxsrv = 0;
- fsrv_to->prev_timed_out = 0;
+ fsrv_to->last_run_timed_out = 0;
fsrv_to->init_child_func = fsrv_exec_child;
@@ -217,7 +217,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
- fsrv->child_timed_out = 0;
+ fsrv->last_run_timed_out = 0;
fsrv->fsrv_pid = fork();
if (fsrv->fsrv_pid < 0) PFATAL("fork() failed");
@@ -361,7 +361,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) {
- fsrv->child_timed_out = 1;
+ fsrv->last_run_timed_out = 1;
kill(fsrv->fsrv_pid, SIGKILL);
} else {
@@ -476,7 +476,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
- if (fsrv->child_timed_out)
+ if (fsrv->last_run_timed_out)
FATAL("Timeout while initializing fork server (adjusting -t may help)");
if (waitpid(fsrv->fsrv_pid, &status, 0) <= 0) PFATAL("waitpid() failed");
@@ -640,6 +640,127 @@ static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
}
+/* Execute target application, monitoring for timeouts. Return status
+ information. The called program will update afl->fsrv->trace_bits. */
+
+fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, volatile u8 *stop_soon_p) {
+
+ s32 res;
+ u32 exec_ms;
+
+ int status = 0;
+
+ u32 timeout = fsrv->exec_tmout;
+
+ /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
+ must prevent any earlier operations from venturing into that
+ territory. */
+
+ memset(fsrv->trace_bits, 0, fsrv->map_size);
+
+ MEM_BARRIER();
+
+ /* we have the fork server (or faux server) up and running
+ First, tell it if the previous run timed out. */
+
+ if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->last_run_timed_out, 4)) != 4) {
+
+ if (*stop_soon_p) return 0;
+ RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+ }
+
+ fsrv->last_run_timed_out = 0;
+
+ if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
+
+ if (stop_soon_p) return 0;
+ RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+
+ }
+
+ if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+
+ exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, stop_soon_p);
+
+ if (exec_ms > timeout) {
+
+ /* If there was no response from forkserver after timeout seconds,
+ we kill the child. The forkserver should inform us afterwards */
+
+ kill(fsrv->child_pid, SIGKILL);
+ fsrv->last_run_timed_out = 1;
+ if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0;
+
+ }
+
+ if (!exec_ms) {
+
+ if (*stop_soon_p) return 0;
+ SAYF("\n" cLRD "[-] " cRST
+ "Unable to communicate with fork server. Some possible reasons:\n\n"
+ " - You've run out of memory. Use -m to increase the the memory "
+ "limit\n"
+ " to something higher than %lld.\n"
+ " - The binary or one of the libraries it uses manages to "
+ "create\n"
+ " threads before the forkserver initializes.\n"
+ " - The binary, at least in some circumstances, exits in a way "
+ "that\n"
+ " also kills the parent process - raise() could be the "
+ "culprit.\n"
+ " - If using persistent mode with QEMU, "
+ "AFL_QEMU_PERSISTENT_ADDR "
+ "is\n"
+ " probably not valid (hint: add the base address in case of "
+ "PIE)"
+ "\n\n"
+ "If all else fails you can disable the fork server via "
+ "AFL_NO_FORKSRV=1.\n",
+ fsrv->mem_limit);
+ RPFATAL(res, "Unable to communicate with fork server");
+
+ }
+
+ if (!WIFSTOPPED(status)) fsrv->child_pid = 0;
+
+ fsrv->total_execs++;
+
+ /* Any subsequent operations on fsrv->trace_bits must not be moved by the
+ compiler below this point. Past this location, fsrv->trace_bits[]
+ behave very normally and do not have to be treated as volatile. */
+
+ MEM_BARRIER();
+
+ /* Report outcome to caller. */
+
+ if (WIFSIGNALED(status) && !*stop_soon_p) {
+
+ fsrv->last_kill_signal = WTERMSIG(status);
+
+ if (fsrv->last_run_timed_out && fsrv->last_kill_signal == SIGKILL)
+ return FSRV_RUN_TMOUT;
+
+ return FSRV_RUN_CRASH;
+
+ }
+
+ /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
+ must use a special exit code. */
+
+ if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
+
+ fsrv->last_kill_signal = 0;
+ return FSRV_RUN_CRASH;
+
+ }
+
+ if ((*(u32 *)fsrv->trace_bits) == EXEC_FAIL_SIG) return FSRV_RUN_NOINST;
+
+ return FSRV_RUN_OK;
+
+}
+
void afl_fsrv_killall() {
LIST_FOREACH(&fsrv_list, afl_forkserver_t, {
@@ -656,4 +777,3 @@ void afl_fsrv_deinit(afl_forkserver_t *fsrv) {
list_remove(&fsrv_list, fsrv);
}
-
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index a0a720fa..66b1e60d 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -598,7 +598,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
- if (unlikely(res == FAULT_ERROR))
+ if (unlikely(res == FSRV_RUN_ERROR))
FATAL("Unable to execute target application");
fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, 0600);
@@ -612,7 +612,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
switch (fault) {
- case FAULT_TMOUT:
+ case FSRV_RUN_TMOUT:
/* Timeouts are not very interesting, but we're still obliged to keep
a handful of samples. We use the presence of new bits in the
@@ -651,9 +651,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
timeout actually uncovers a crash. Make sure we don't discard it if
so. */
- if (!afl->stop_soon && new_fault == FAULT_CRASH) goto keep_as_crash;
+ if (!afl->stop_soon && new_fault == FSRV_RUN_CRASH) goto keep_as_crash;
- if (afl->stop_soon || new_fault != FAULT_TMOUT) return keeping;
+ if (afl->stop_soon || new_fault != FSRV_RUN_TMOUT) return keeping;
}
@@ -675,7 +675,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
break;
- case FAULT_CRASH:
+ case FSRV_RUN_CRASH:
keep_as_crash:
@@ -704,7 +704,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES
snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
- afl->unique_crashes, afl->kill_signal, describe_op(afl, 0));
+ afl->unique_crashes, afl->fsrv.last_kill_signal, describe_op(afl, 0));
#else
@@ -730,11 +730,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
afl->last_crash_time = get_cur_time();
- afl->last_crash_execs = afl->total_execs;
+ afl->last_crash_execs = afl->fsrv.total_execs;
break;
- case FAULT_ERROR: FATAL("Unable to execute target application");
+ case FSRV_RUN_ERROR: FATAL("Unable to execute target application");
default: return keeping;
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index e2747097..ab93d838 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -66,7 +66,7 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
if (afl->stop_soon) return 1;
- if (fault == FAULT_TMOUT) {
+ if (fault == FSRV_RUN_TMOUT) {
if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 10417da6..55f7ce53 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -493,13 +493,13 @@ void perform_dry_run(afl_state_t *afl) {
if (afl->stop_soon) return;
- if (res == afl->crash_mode || res == FAULT_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 FAULT_NONE:
+ case FSRV_RUN_OK:
if (q == afl->queue) check_map_coverage(afl);
@@ -507,7 +507,7 @@ void perform_dry_run(afl_state_t *afl) {
break;
- case FAULT_TMOUT:
+ case FSRV_RUN_TMOUT:
if (afl->timeout_given) {
@@ -556,7 +556,7 @@ void perform_dry_run(afl_state_t *afl) {
}
- case FAULT_CRASH:
+ case FSRV_RUN_CRASH:
if (afl->crash_mode) break;
@@ -650,13 +650,13 @@ void perform_dry_run(afl_state_t *afl) {
FATAL("Test case '%s' results in a crash", fn);
- case FAULT_ERROR:
+ case FSRV_RUN_ERROR:
FATAL("Unable to execute target application ('%s')", afl->argv[0]);
- case FAULT_NOINST: FATAL("No instrumentation detected");
+ case FSRV_RUN_NOINST: FATAL("No instrumentation detected");
- case FAULT_NOBITS:
+ case FSRV_RUN_NOBITS:
++afl->useless_at_start;
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index efb1c117..7bf23e84 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -242,7 +242,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
++afl->trim_execs;
- if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; }
+ if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 961a29d6..cc97654a 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -442,14 +442,14 @@ u8 fuzz_one_original(afl_state_t *afl) {
if (unlikely(afl->queue_cur->cal_failed)) {
- u8 res = FAULT_TMOUT;
+ u8 res = FSRV_RUN_TMOUT;
if (afl->queue_cur->cal_failed < CAL_CHANCES) {
res =
calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
- if (unlikely(res == FAULT_ERROR))
+ if (unlikely(res == FSRV_RUN_ERROR))
FATAL("Unable to execute target application");
}
@@ -471,7 +471,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
u8 res = trim_case(afl, afl->queue_cur, in_buf);
- if (unlikely(res == FAULT_ERROR))
+ if (unlikely(res == FSRV_RUN_ERROR))
FATAL("Unable to execute target application");
if (unlikely(afl->stop_soon)) {
@@ -2469,14 +2469,14 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
if (afl->queue_cur->cal_failed) {
- u8 res = FAULT_TMOUT;
+ u8 res = FSRV_RUN_TMOUT;
if (afl->queue_cur->cal_failed < CAL_CHANCES) {
res =
calibrate_case(afl, afl->queue_cur, in_buf, afl->queue_cycle - 1, 0);
- if (res == FAULT_ERROR) FATAL("Unable to execute target application");
+ if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application");
}
@@ -2497,7 +2497,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
u8 res = trim_case(afl, afl->queue_cur, in_buf);
- if (res == FAULT_ERROR) FATAL("Unable to execute target application");
+ if (res == FSRV_RUN_ERROR) FATAL("Unable to execute target application");
if (afl->stop_soon) {
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 5eb110d0..d05eee08 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -492,7 +492,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
// the more often fuzz result paths are equal to this queue entry,
// reduce its value
perf_score *=
- (1 - (double)((double)q->n_fuzz / (double)afl->total_execs));
+ (1 - (double)((double)q->n_fuzz / (double)afl->fsrv.total_execs));
break;
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 6a01ec89..8cea01e8 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -622,7 +622,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1;
u64 orig_hit_cnt, new_hit_cnt;
- u64 orig_execs = afl->total_execs;
+ u64 orig_execs = afl->fsrv.total_execs;
orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
afl->stage_name = "input-to-state";
@@ -670,7 +670,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
exit_its:
new_hit_cnt = afl->queued_paths + afl->unique_crashes;
afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt;
- afl->stage_cycles[STAGE_ITS] += afl->total_execs - orig_execs;
+ afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs;
memcpy(orig_buf, buf, len);
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 514ba9ef..b20c5436 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -32,95 +32,9 @@
/* Execute target application, monitoring for timeouts. Return status
information. The called program will update afl->fsrv->trace_bits. */
-u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
+fsrv_run_result_t run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
- s32 res;
- u32 exec_ms;
-
- int status = 0;
- u32 tb4;
-
- fsrv->child_timed_out = 0;
-
- /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
- must prevent any earlier operations from venturing into that
- territory. */
-
- memset(fsrv->trace_bits, 0, fsrv->map_size);
-
- MEM_BARRIER();
-
- /* we have the fork server (or faux server) up and running, so simply
- tell it to have at it, and then read back PID. */
-
- if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) {
-
- if (afl->stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
-
- if (afl->stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
-
- exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon);
-
- if (exec_ms > timeout) {
-
- /* If there was no response from forkserver after timeout seconds,
- we kill the child. The forkserver should inform us afterwards */
-
- kill(fsrv->child_pid, SIGKILL);
- fsrv->child_timed_out = 1;
- if (read(fsrv->fsrv_st_fd, &status, 4) < 4) exec_ms = 0;
-
- }
-
- if (!exec_ms) {
-
- if (afl->stop_soon) return 0;
- SAYF("\n" cLRD "[-] " cRST
- "Unable to communicate with fork server. Some possible reasons:\n\n"
- " - You've run out of memory. Use -m to increase the the memory "
- "limit\n"
- " to something higher than %lld.\n"
- " - The binary or one of the libraries it uses manages to "
- "create\n"
- " threads before the forkserver initializes.\n"
- " - The binary, at least in some circumstances, exits in a way "
- "that\n"
- " also kills the parent process - raise() could be the "
- "culprit.\n"
- " - If using persistent mode with QEMU, "
- "AFL_QEMU_PERSISTENT_ADDR "
- "is\n"
- " probably not valid (hint: add the base address in case of "
- "PIE)"
- "\n\n"
- "If all else fails you can disable the fork server via "
- "AFL_NO_FORKSRV=1.\n",
- fsrv->mem_limit);
- RPFATAL(res, "Unable to communicate with fork server");
-
- }
-
- if (!WIFSTOPPED(status)) fsrv->child_pid = 0;
-
- ++afl->total_execs;
-
- /* Any subsequent operations on fsrv->trace_bits must not be moved by the
- compiler below this point. Past this location, fsrv->trace_bits[]
- behave very normally and do not have to be treated as volatile. */
-
- MEM_BARRIER();
-
- tb4 = *(u32 *)fsrv->trace_bits;
+ fsrv_run_result_t res = afl_fsrv_run_target(&afl->fsrv, &afl->stop_soon);
#ifdef WORD_SIZE_64
classify_counts(afl, (u64 *)fsrv->trace_bits);
@@ -128,35 +42,7 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
classify_counts(afl, (u32 *)fsrv->trace_bits);
#endif /* ^WORD_SIZE_64 */
- fsrv->prev_timed_out = fsrv->child_timed_out;
-
- /* Report outcome to caller. */
-
- if (WIFSIGNALED(status) && !afl->stop_soon) {
-
- afl->kill_signal = WTERMSIG(status);
-
- if (fsrv->child_timed_out && afl->kill_signal == SIGKILL)
- return FAULT_TMOUT;
-
- return FAULT_CRASH;
-
- }
-
- /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
- must use a special exit code. */
-
- if (fsrv->uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
-
- afl->kill_signal = 0;
- return FAULT_CRASH;
-
- }
-
- if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG)
- return FAULT_ERROR;
-
- return FAULT_NONE;
+ return res;
}
@@ -348,7 +234,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
if (!afl->dumb_mode && !afl->stage_cur &&
!count_bytes(afl, afl->fsrv.trace_bits)) {
- fault = FAULT_NOINST;
+ fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
@@ -408,7 +294,7 @@ 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) fault = FAULT_NOBITS;
+ if (!afl->dumb_mode && first_run && !fault && !new_bits) fault = FSRV_RUN_NOBITS;
abort_calibration:
@@ -645,7 +531,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
fault = run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
++afl->trim_execs;
- if (afl->stop_soon || fault == FAULT_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?
*/
@@ -753,7 +639,7 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
if (afl->stop_soon) return 1;
- if (fault == FAULT_TMOUT) {
+ if (fault == FSRV_RUN_TMOUT) {
if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index d48dd5e3..52148dc2 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -108,14 +108,14 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
afl->start_time / 1000, cur_time / 1000,
(cur_time - afl->start_time) / 1000, getpid(),
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
- afl->total_execs,
- afl->total_execs / ((double)(get_cur_time() - afl->start_time) / 1000),
+ afl->fsrv.total_execs,
+ afl->fsrv.total_execs / ((double)(get_cur_time() - afl->start_time) / 1000),
afl->queued_paths, afl->queued_favored, afl->queued_discovered,
afl->queued_imported, afl->max_depth, afl->current_entry,
afl->pending_favored, afl->pending_not_fuzzed, afl->queued_variable,
stability, bitmap_cvg, afl->unique_crashes, afl->unique_hangs,
afl->last_path_time / 1000, afl->last_crash_time / 1000,
- afl->last_hang_time / 1000, afl->total_execs - afl->last_crash_execs,
+ afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
afl->fsrv.exec_tmout, afl->slowest_exec_ms,
#ifdef __APPLE__
(unsigned long int)(rus.ru_maxrss >> 20),
@@ -227,7 +227,7 @@ void show_stats(afl_state_t *afl) {
if (afl->most_execs_key == 1) {
- if (afl->most_execs <= afl->total_execs) {
+ if (afl->most_execs <= afl->fsrv.total_execs) {
afl->most_execs_key = 2;
afl->stop_soon = 2;
@@ -251,11 +251,11 @@ void show_stats(afl_state_t *afl) {
if (!afl->stats_last_execs) {
afl->stats_avg_exec =
- ((double)afl->total_execs) * 1000 / (cur_ms - afl->start_time);
+ ((double)afl->fsrv.total_execs) * 1000 / (cur_ms - afl->start_time);
} else {
- double cur_avg = ((double)(afl->total_execs - afl->stats_last_execs)) *
+ double cur_avg = ((double)(afl->fsrv.total_execs - afl->stats_last_execs)) *
1000 / (cur_ms - afl->stats_last_ms);
/* If there is a dramatic (5x+) jump in speed, reset the indicator
@@ -270,7 +270,7 @@ void show_stats(afl_state_t *afl) {
}
afl->stats_last_ms = cur_ms;
- afl->stats_last_execs = afl->total_execs;
+ afl->stats_last_execs = afl->fsrv.total_execs;
/* Tell the callers when to contact us (as measured in execs). */
@@ -543,14 +543,14 @@ void show_stats(afl_state_t *afl) {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" new crashes : %s%-22s" bSTG bV "\n",
- u_stringify_int(IB(0), afl->total_execs),
+ u_stringify_int(IB(0), afl->fsrv.total_execs),
afl->unique_crashes ? cLRD : cRST, tmp);
} else {
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
" total crashes : %s%-22s" bSTG bV "\n",
- u_stringify_int(IB(0), afl->total_execs),
+ u_stringify_int(IB(0), afl->fsrv.total_execs),
afl->unique_crashes ? cLRD : cRST, tmp);
}
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 07067691..9f17b61b 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -480,7 +480,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'C': /* crash mode */
if (afl->crash_mode) FATAL("Multiple -C options not supported");
- afl->crash_mode = FAULT_CRASH;
+ afl->crash_mode = FSRV_RUN_CRASH;
break;
case 'n': /* dumb mode */
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index eea1cc95..16d6fe41 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -40,7 +40,6 @@
#include <stdio.h>
#include <unistd.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 3fcc1d2b..5f622c25 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -69,7 +69,7 @@ static u8 *in_data; /* Input data */
static u32 total, highest; /* tuple content information */
static u32 in_len, /* Input data length */
- arg_offset, total_execs; /* Total number of execs */
+ arg_offset; /* Total number of execs */
static u8 quiet_mode, /* Hide non-essential messages? */
edges_only, /* Ignore hit counts? */
@@ -193,7 +193,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (cmin_mode) {
- if (fsrv->child_timed_out) break;
+ if (fsrv->last_run_timed_out) break;
if (!caa && child_crashed != cco) break;
fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
@@ -233,75 +233,18 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
}
-/* Execute target application. Returns 0 if the changes are a dud, or
- 1 if they should be kept. */
+/* Execute target application. */
-static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem,
+void run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem,
u32 len) {
- struct itimerval it;
- int status = 0;
-
- memset(fsrv->trace_bits, 0, MAP_SIZE);
- MEM_BARRIER();
-
write_to_testcase(fsrv, mem, len);
- s32 res;
-
- /* we have the fork server up and running, so simply
- tell it to have at it, and then read back PID. */
-
- if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
-
- /* Configure timeout, wait for child, cancel timeout. */
-
- if (fsrv->exec_tmout) {
-
- it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
- it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
-
- }
-
- setitimer(ITIMER_REAL, &it, NULL);
-
- if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to communicate with fork server (OOM?)");
-
- }
-
- fsrv->child_pid = 0;
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = 0;
-
- setitimer(ITIMER_REAL, &it, NULL);
-
- MEM_BARRIER();
-
- /* Clean up bitmap, analyze exit condition, etc. */
-
- if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
- FATAL("Unable to execute '%s'", argv[0]);
+ fsrv_run_result_t res = afl_fsrv_run_target(fsrv, &stop_soon);
+ if (res == FSRV_RUN_NOINST || res == FSRV_RUN_ERROR) FATAL("Error running target");
classify_counts(fsrv->trace_bits,
binary_mode ? count_class_binary : count_class_human);
- total_execs++;
if (stop_soon) {
@@ -310,22 +253,6 @@ static u8 run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem,
}
- /* Always discard inputs that time out. */
-
- if (fsrv->child_timed_out) { return 0; }
-
- /* Handle crashing inputs depending on current mode. */
-
- if (WIFSIGNALED(status) ||
- (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
- (WIFEXITED(status) && WEXITSTATUS(status))) {
-
- return 0;
-
- }
-
- return 0;
-
}
/* Read initial file. */
@@ -425,7 +352,7 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) {
if (fsrv->exec_tmout) {
- fsrv->child_timed_out = 0;
+ fsrv->last_run_timed_out = 0;
it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
@@ -452,12 +379,12 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) {
if (!quiet_mode) SAYF(cRST "-- Program output ends --\n");
- if (!fsrv->child_timed_out && !stop_soon && WIFSIGNALED(status))
+ if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status))
child_crashed = 1;
if (!quiet_mode) {
- if (fsrv->child_timed_out)
+ if (fsrv->last_run_timed_out)
SAYF(cLRD "\n+++ Program timed off +++\n" cRST);
else if (stop_soon)
SAYF(cLRD "\n+++ Program aborted by user +++\n" cRST);
@@ -980,7 +907,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (!quiet_mode) OKF("Processed %u input files.", total_execs);
+ if (!quiet_mode) OKF("Processed %llu input files.", fsrv->total_execs);
closedir(dir_in);
if (dir_out) closedir(dir_out);
@@ -1010,7 +937,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_shm_deinit(&shm);
- u32 ret = child_crashed * 2 + fsrv->child_timed_out;
+ u32 ret = child_crashed * 2 + fsrv->last_run_timed_out;
if (fsrv->target_path) ck_free(fsrv->target_path);
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 31fad1df..999d5f65 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -67,7 +67,6 @@ static u8 *in_data; /* Input data for trimming */
static u32 in_len, /* Input data length */
orig_cksum, /* Original checksum */
- total_execs, /* Total number of execs */
missed_hangs, /* Misses due to hangs */
missed_crashes, /* Misses due to crashes */
missed_paths; /* Misses due to exec path diffs */
@@ -249,69 +248,11 @@ static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
u8 first_run) {
- struct itimerval it;
- int status = 0;
-
- u32 cksum;
-
- fsrv->child_timed_out = 0;
-
- memset(fsrv->trace_bits, 0, fsrv->map_size);
- MEM_BARRIER();
-
write_to_testcase(fsrv, mem, len);
- s32 res;
-
- /* we have the fork server up and running, so simply
- tell it to have at it, and then read back PID. */
-
- if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->prev_timed_out, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if ((res = read(fsrv->fsrv_st_fd, &fsrv->child_pid, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
-
- /* Configure timeout, wait for child, cancel timeout. */
-
- if (fsrv->exec_tmout) {
-
- it.it_value.tv_sec = (fsrv->exec_tmout / 1000);
- it.it_value.tv_usec = (fsrv->exec_tmout % 1000) * 1000;
-
- }
-
- setitimer(ITIMER_REAL, &it, NULL);
+ fsrv_run_result_t ret = afl_fsrv_run_target(fsrv, &stop_soon);
- if ((res = read(fsrv->fsrv_st_fd, &status, 4)) != 4) {
-
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to communicate with fork server (OOM?)");
-
- }
-
- fsrv->child_pid = 0;
- it.it_value.tv_sec = 0;
- it.it_value.tv_usec = 0;
-
- setitimer(ITIMER_REAL, &it, NULL);
-
- MEM_BARRIER();
-
- /* Clean up bitmap, analyze exit condition, etc. */
-
- if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
- FATAL("Unable to execute '%s'", argv[0]);
+ if (ret == FSRV_RUN_ERROR) FATAL("Couldn't run child");
if (!hang_mode) {
@@ -320,8 +261,6 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
}
- total_execs++;
-
if (stop_soon) {
SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST);
@@ -334,25 +273,21 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
if (hang_mode) {
- if (fsrv->child_timed_out) return 1;
-
- if (WIFSIGNALED(status) ||
- (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
- (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
-
+ switch (ret)
+ {
+ case FSRV_RUN_TMOUT:
+ return 1;
+ case FSRV_RUN_CRASH:
missed_crashes++;
-
- } else {
-
+ return 0;
+ default:
missed_hangs++;
-
+ return 0;
}
- return 0;
-
}
- if (fsrv->child_timed_out) {
+ if (ret == FSRV_RUN_TMOUT) {
missed_hangs++;
return 0;
@@ -361,9 +296,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
/* Handle crashing inputs depending on current mode. */
- if (WIFSIGNALED(status) ||
- (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
- (WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
+ if (ret == FSRV_RUN_CRASH) {
if (first_run) crash_mode = 1;
@@ -391,7 +324,9 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
}
- cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST);
+ if (ret == FSRV_RUN_NOINST) FATAL("Binary not instrumented?");
+
+ u32 cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST);
if (first_run) orig_cksum = cksum;
@@ -640,11 +575,11 @@ finalize_all:
SAYF("\n" cGRA " File size reduced by : " cRST
"%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
- "%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA
+ "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA
" Fruitless execs : " cRST "termination=%u crash=%u\n\n",
100 - ((double)in_len) * 100 / orig_len, in_len,
in_len == 1 ? "" : "s",
- ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
+ ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), fsrv->total_execs,
missed_paths, missed_crashes);
return;
@@ -652,13 +587,13 @@ finalize_all:
SAYF("\n" cGRA " File size reduced by : " cRST
"%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
- "%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA
+ "%0.02f%%\n" cGRA " Number of execs done : " cRST "%llu\n" cGRA
" Fruitless execs : " cRST "path=%u crash=%u hang=%s%u\n\n",
100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
- ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
+ ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), fsrv->total_execs,
missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs);
- if (total_execs > 50 && missed_hangs * 10 > total_execs && !hang_mode)
+ if (fsrv->total_execs > 50 && missed_hangs * 10 > fsrv->total_execs && !hang_mode)
WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
}
@@ -1139,13 +1074,13 @@ int main(int argc, char **argv_orig, char **envp) {
run_target(fsrv, use_argv, in_data, in_len, 1);
- if (hang_mode && !fsrv->child_timed_out)
+ if (hang_mode && !fsrv->last_run_timed_out)
FATAL(
"Target binary did not time out but hang minimization mode "
"(-H) was set (-t %u).",
fsrv->exec_tmout);
- if (fsrv->child_timed_out && !hang_mode)
+ if (fsrv->last_run_timed_out && !hang_mode)
FATAL(
"Target binary times out (adjusting -t may help). Use -H to minimize a "
"hang.");