aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c100
-rw-r--r--src/afl-common.c160
-rw-r--r--src/afl-forkserver.c391
-rw-r--r--src/afl-fuzz-bitmap.c114
-rw-r--r--src/afl-fuzz-cmplog.c478
-rw-r--r--src/afl-fuzz-extras.c12
-rw-r--r--src/afl-fuzz-init.c52
-rw-r--r--src/afl-fuzz-mutators.c20
-rw-r--r--src/afl-fuzz-one.c83
-rw-r--r--src/afl-fuzz-python.c4
-rw-r--r--src/afl-fuzz-queue.c20
-rw-r--r--src/afl-fuzz-redqueen.c240
-rw-r--r--src/afl-fuzz-run.c230
-rw-r--r--src/afl-fuzz-state.c52
-rw-r--r--src/afl-fuzz-stats.c86
-rw-r--r--src/afl-fuzz.c235
-rw-r--r--src/afl-gcc.c19
-rw-r--r--src/afl-sharedmem.c17
-rw-r--r--src/afl-showmap.c287
-rw-r--r--src/afl-tmin.c351
-rw-r--r--src/third_party/libradamsa/libradamsa.c82
-rw-r--r--src/third_party/libradamsa/radamsa.h14
22 files changed, 1370 insertions, 1677 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 427fbe6d..b2c0f841 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -36,6 +36,7 @@
#include "hash.h"
#include "sharedmem.h"
#include "common.h"
+#include "forkserver.h"
#include <stdio.h>
#include <unistd.h>
@@ -57,7 +58,7 @@
static s32 child_pid; /* PID of the tested program */
-u8 *trace_bits; /* SHM with instrumentation bitmap */
+static u8 *trace_bits; /* SHM with instrumentation bitmap */
static u8 *in_file, /* Analyzer input test case */
*prog_in; /* Targeted program input file */
@@ -74,16 +75,16 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static s32 dev_null_fd = -1; /* FD to /dev/null */
-u8 edges_only, /* Ignore hit counts? */
+static u8 edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */
use_stdin = 1; /* Use stdin for program input? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_timed_out; /* Child timed out? */
-static u8 qemu_mode;
-
static u8 *target_path;
+static u8 qemu_mode;
+static u32 map_size = MAP_SIZE;
/* Constants used for describing byte behavior. */
@@ -115,7 +116,7 @@ static u8 count_class_lookup[256] = {
static void classify_counts(u8 *mem) {
- u32 i = MAP_SIZE;
+ u32 i = map_size;
if (edges_only) {
@@ -144,7 +145,7 @@ static void classify_counts(u8 *mem) {
static inline u8 anything_set(void) {
u32 *ptr = (u32 *)trace_bits;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (map_size >> 2);
while (i--)
if (*(ptr++)) return 1;
@@ -209,7 +210,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
/* Execute target application. Returns exec checksum, or 0 if program
times out. */
-static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
+static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
static struct itimerval it;
int status = 0;
@@ -217,7 +218,7 @@ static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
s32 prog_in_fd;
u32 cksum;
- memset(trace_bits, 0, MAP_SIZE);
+ memset(trace_bits, 0, map_size);
MEM_BARRIER();
prog_in_fd = write_to_file(prog_in, mem, len);
@@ -311,7 +312,7 @@ static u32 run_target(char **argv, u8 *mem, u32 len, u8 first_run) {
}
- cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST);
+ cksum = hash32(trace_bits, map_size, HASH_CONST);
/* We don't actually care if the target is crashing or not,
except that when it does, the checksum should be different. */
@@ -560,16 +561,16 @@ static void analyze(char **argv) {
code. */
in_data[i] ^= 0xff;
- xor_ff = run_target(argv, in_data, in_len, 0);
+ xor_ff = analyze_run_target(argv, in_data, in_len, 0);
in_data[i] ^= 0xfe;
- xor_01 = run_target(argv, in_data, in_len, 0);
+ xor_01 = analyze_run_target(argv, in_data, in_len, 0);
in_data[i] = (in_data[i] ^ 0x01) - 0x10;
- sub_10 = run_target(argv, in_data, in_len, 0);
+ sub_10 = analyze_run_target(argv, in_data, in_len, 0);
in_data[i] += 0x20;
- add_10 = run_target(argv, in_data, in_len, 0);
+ add_10 = analyze_run_target(argv, in_data, in_len, 0);
in_data[i] -= 0x10;
/* Classify current behavior. */
@@ -795,8 +796,10 @@ static void usage(u8 *argv0) {
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
- "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
@@ -805,61 +808,6 @@ static void usage(u8 *argv0) {
}
-/* Find binary. */
-
-static void find_binary(u8 *fname) {
-
- u8 * env_path = 0;
- struct stat st;
-
- if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
- target_path = ck_strdup(fname);
-
- if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
- !(st.st_mode & 0111) || st.st_size < 4)
- FATAL("Program '%s' not found or not executable", fname);
-
- } else {
-
- while (env_path) {
-
- u8 *cur_elem, *delim = strchr(env_path, ':');
-
- if (delim) {
-
- cur_elem = ck_alloc(delim - env_path + 1);
- memcpy(cur_elem, env_path, delim - env_path);
- delim++;
-
- } else
-
- cur_elem = ck_strdup(env_path);
-
- env_path = delim;
-
- if (cur_elem[0])
- target_path = alloc_printf("%s/%s", cur_elem, fname);
- else
- target_path = ck_strdup(fname);
-
- ck_free(cur_elem);
-
- if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
- (st.st_mode & 0111) && st.st_size >= 4)
- break;
-
- ck_free(target_path);
- target_path = 0;
-
- }
-
- if (!target_path) FATAL("Program '%s' not found or not executable", fname);
-
- }
-
-}
-
/* Main entry point */
int main(int argc, char **argv, char **envp) {
@@ -902,6 +850,8 @@ int main(int argc, char **argv, char **envp) {
if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1;
+ if (!optarg) { FATAL("Wrong usage of -m"); }
+
if (!strcmp(optarg, "none")) {
mem_limit = 0;
@@ -938,6 +888,8 @@ int main(int argc, char **argv, char **envp) {
if (timeout_given) FATAL("Multiple -t options not supported");
timeout_given = 1;
+ if (!optarg) FATAL("Wrong usage of -t");
+
exec_tmout = atoi(optarg);
if (exec_tmout < 10 || optarg[0] == '-')
@@ -982,18 +934,20 @@ int main(int argc, char **argv, char **envp) {
if (optind == argc || !in_file) usage(argv[0]);
+ map_size = get_map_size();
+
use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX");
check_environment_vars(envp);
sharedmem_t shm = {0};
- trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+ trace_bits = afl_shm_init(&shm, map_size, 0);
atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment();
- find_binary(argv[optind]);
+ target_path = find_binary(argv[optind]);
detect_file_args(argv + optind, prog_in, &use_stdin);
if (qemu_mode) {
@@ -1016,7 +970,7 @@ int main(int argc, char **argv, char **envp) {
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
mem_limit, exec_tmout, edges_only ? ", edges only" : "");
- run_target(use_argv, in_data, in_len, 1);
+ analyze_run_target(use_argv, in_data, in_len, 1);
if (child_timed_out)
FATAL("Target binary times out (adjusting -t may help).");
@@ -1028,6 +982,8 @@ int main(int argc, char **argv, char **envp) {
OKF("We're done here. Have a nice day!\n");
+ if (target_path) ck_free(target_path);
+
afl_shm_deinit(&shm);
exit(0);
diff --git a/src/afl-common.c b/src/afl-common.c
index 73b3fa8a..6ef7a195 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -37,9 +37,14 @@
#include <unistd.h>
#endif
#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
u8 be_quiet = 0;
u8 *doc_path = "";
+u8 last_intr = 0;
char *afl_environment_variables[] = {
@@ -58,15 +63,16 @@ char *afl_environment_variables[] = {
"AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER",
"AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM",
"AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD",
+ "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY",
"AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES",
"AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS",
"AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES",
"AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO",
"AFL_LLVM_WHITELIST", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID",
"AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN",
- "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI",
+ "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_PYTHON",
"AFL_NO_X86", // not really an env but we dont want to warn on it
- "AFL_PATH", "AFL_PERFORMANCE_FILE",
+ "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE",
//"AFL_PERSISTENT", // not implemented anymore, so warn additionally
"AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV",
"AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_DISABLE_CACHE",
@@ -139,7 +145,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
char **argv_cpy_dup(int argc, char **argv) {
- u32 i = 0;
+ int i = 0;
char **ret = ck_alloc((argc + 1) * sizeof(char *));
@@ -216,10 +222,12 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
}
- } else
+ } else {
ck_free(own_copy);
+ }
+
if (!access(BIN_PATH "/afl-qemu-trace", X_OK)) {
if (cp) ck_free(cp);
@@ -233,7 +241,7 @@ char **get_qemu_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
"Oops, unable to find the 'afl-qemu-trace' binary. The binary must be "
"built\n"
" separately by following the instructions in "
- "afl->qemu_mode/README.md. "
+ "qemu_mode/README.md. "
"If you\n"
" already have the binary installed, you may need to specify "
"AFL_PATH in the\n"
@@ -290,11 +298,10 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
*rsl = 0;
cp = alloc_printf("%s/afl-qemu-trace", own_copy);
- ck_free(own_copy);
- if (!access(cp, X_OK)) {
+ if (cp && !access(cp, X_OK)) {
- if (cp != NULL) ck_free(cp);
+ ck_free(cp);
cp = alloc_printf("%s/afl-wine-trace", own_copy);
@@ -307,10 +314,14 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
}
- } else
+ ck_free(own_copy);
+
+ } else {
ck_free(own_copy);
+ }
+
u8 *ncp = BIN_PATH "/afl-qemu-trace";
if (!access(ncp, X_OK)) {
@@ -330,7 +341,7 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
"Oops, unable to find the '%s' binary. The binary must be "
"built\n"
" separately by following the instructions in "
- "afl->qemu_mode/README.md. "
+ "qemu_mode/README.md. "
"If you\n"
" already have the binary installed, you may need to specify "
"AFL_PATH in the\n"
@@ -348,12 +359,85 @@ char **get_wine_argv(u8 *own_loc, u8 **target_path_p, int argc, char **argv) {
}
+/* Find binary, used by analyze, showmap, tmin
+ @returns the path, allocating the string */
+
+u8 *find_binary(u8 *fname) {
+
+ // TODO: Merge this function with check_binary of afl-fuzz-init.c
+
+ u8 *env_path = NULL;
+ u8 *target_path = NULL;
+
+ struct stat st;
+
+ if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
+
+ target_path = ck_strdup(fname);
+
+ if (stat(target_path, &st) || !S_ISREG(st.st_mode) ||
+ !(st.st_mode & 0111) || st.st_size < 4) {
+
+ free(target_path);
+ FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ } else {
+
+ while (env_path) {
+
+ u8 *cur_elem, *delim = strchr(env_path, ':');
+
+ if (delim) {
+
+ cur_elem = ck_alloc(delim - env_path + 1);
+ memcpy(cur_elem, env_path, delim - env_path);
+ delim++;
+
+ } else {
+
+ cur_elem = ck_strdup(env_path);
+
+ }
+
+ env_path = delim;
+
+ if (cur_elem[0]) {
+
+ target_path = alloc_printf("%s/%s", cur_elem, fname);
+
+ } else {
+
+ target_path = ck_strdup(fname);
+
+ }
+
+ ck_free(cur_elem);
+
+ if (!stat(target_path, &st) && S_ISREG(st.st_mode) &&
+ (st.st_mode & 0111) && st.st_size >= 4)
+ break;
+
+ ck_free(target_path);
+ target_path = NULL;
+
+ }
+
+ if (!target_path) FATAL("Program '%s' not found or not executable", fname);
+
+ }
+
+ return target_path;
+
+}
+
void check_environment_vars(char **envp) {
if (be_quiet) return;
int index = 0, found = 0;
- char *env;
+ char *env, *val;
while ((env = envp[index++]) != NULL) {
if (strncmp(env, "ALF_", 4) == 0) {
@@ -367,10 +451,21 @@ void check_environment_vars(char **envp) {
while (match == 0 && afl_environment_variables[i] != NULL)
if (strncmp(env, afl_environment_variables[i],
strlen(afl_environment_variables[i])) == 0 &&
- env[strlen(afl_environment_variables[i])] == '=')
+ env[strlen(afl_environment_variables[i])] == '=') {
+
match = 1;
- else
+ if ((val = getenv(afl_environment_variables[i])) && !*val)
+ WARNF(
+ "AFL environment variable %s defined but is empty, this can "
+ "lead to unexpected consequences",
+ afl_environment_variables[i]);
+
+ } else {
+
i++;
+
+ }
+
if (match == 0) {
WARNF("Mistyped AFL environment variable: %s", env);
@@ -398,6 +493,20 @@ char *get_afl_env(char *env) {
}
+/* Read mask bitmap from file. This is for the -B option. */
+
+void read_bitmap(u8 *fname, u8 *map, size_t len) {
+
+ s32 fd = open(fname, O_RDONLY);
+
+ if (fd < 0) PFATAL("Unable to open '%s'", fname);
+
+ ck_read(fd, map, len, fname);
+
+ close(fd);
+
+}
+
u64 get_cur_time(void) {
struct timeval tv;
@@ -743,7 +852,8 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
Returns the time passed to read.
If the wait times out, returns timeout_ms + 1;
Returns 0 if an error occurred (fd closed, signal, ...); */
-u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
+u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms,
+ volatile u8 *stop_soon_p) {
struct timeval timeout;
fd_set readfds;
@@ -768,8 +878,8 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
} else if (sret < 0) {
- // perror("sret malloc");
- // TODO: catch other (errno == EINTR) than ctrl+c?
+ /* Retry select for all signals other than than ctrl+c */
+ if (errno == EINTR && !*stop_soon_p) { continue; }
return 0;
}
@@ -788,3 +898,21 @@ u32 read_timed(s32 fd, void *buf, size_t len, u32 timeout_ms) {
}
+u32 get_map_size() {
+
+ uint32_t map_size = MAP_SIZE;
+ char * ptr;
+
+ if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) {
+
+ map_size = atoi(ptr);
+ if (map_size < 8 || map_size > (1 << 29))
+ FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size);
+ if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3);
+
+ }
+
+ return map_size;
+
+}
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 11b359da..9b915a7a 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -8,7 +8,9 @@
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
+
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -38,10 +40,12 @@
#include <time.h>
#include <errno.h>
#include <signal.h>
+#include <fcntl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <sys/select.h>
+#include <sys/stat.h>
/**
* The correct fds for reading and writing pipes
@@ -51,6 +55,12 @@
list_t fsrv_list = {.element_prealloc_count = 0};
+static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
+
+ execv(fsrv->target_path, argv);
+
+}
+
/* Initializes the struct */
void afl_fsrv_init(afl_forkserver_t *fsrv) {
@@ -58,33 +68,68 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
// this structure needs default so we initialize it if this was not done
// already
- fsrv->use_stdin = 1;
fsrv->out_fd = -1;
fsrv->out_dir_fd = -1;
fsrv->dev_null_fd = -1;
#ifndef HAVE_ARC4RANDOM
fsrv->dev_urandom_fd = -1;
#endif
+ /* Settings */
+ fsrv->use_stdin = 1;
+ fsrv->no_unlink = 0;
fsrv->exec_tmout = EXEC_TIMEOUT;
fsrv->mem_limit = MEM_LIMIT;
- fsrv->child_pid = -1;
- fsrv->out_dir_fd = -1;
+ fsrv->out_file = NULL;
+ /* exec related stuff */
+ 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;
list_append(&fsrv_list, fsrv);
}
+/* Initialize a new forkserver instance, duplicating "global" settings */
+void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
+
+ fsrv_to->use_stdin = from->use_stdin;
+ fsrv_to->out_fd = from->out_fd;
+ fsrv_to->dev_null_fd = from->dev_null_fd;
+ fsrv_to->exec_tmout = from->exec_tmout;
+ fsrv_to->mem_limit = from->mem_limit;
+ fsrv_to->map_size = from->map_size;
+
+#ifndef HAVE_ARC4RANDOM
+ fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
+#endif
+
+ // These are forkserver specific.
+ fsrv_to->out_dir_fd = -1;
+ fsrv_to->child_pid = -1;
+ fsrv_to->use_fauxsrv = 0;
+ fsrv_to->last_run_timed_out = 0;
+ fsrv_to->out_file = NULL;
+
+ fsrv_to->init_child_func = fsrv_exec_child;
+
+ list_append(&fsrv_list, fsrv_to);
+
+}
+
/* Internal forkserver for dumb_mode=1 and non-forkserver mode runs.
It execvs for each fork, forwarding exit codes and child pids to afl. */
static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
- unsigned char tmp[4] = {0};
+ unsigned char tmp[4] = {0, 0, 0, 0};
pid_t child_pid = -1;
+ if (!be_quiet) ACTF("Using Fauxserver:");
+
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
@@ -160,19 +205,29 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
cloning a stopped child. So, we just execute once, and then send commands
through a pipe. The other part of this logic is in afl-as.h / llvm_mode */
-void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
+void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
+ volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2];
int status;
s32 rlen;
- if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:");
+ if (!be_quiet) ACTF("Spinning up the fork server...");
+
+ if (fsrv->use_fauxsrv) {
+
+ /* TODO: Come up with sone nice way to initalize this all */
+
+ if (fsrv->init_child_func != fsrv_exec_child)
+ FATAL("Different forkserver not compatible with fauxserver");
- if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server...");
+ fsrv->init_child_func = afl_fauxsrv_execv;
+
+ }
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");
@@ -220,7 +275,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
setsid();
- if (!get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) {
+ if (!(debug_child_output)) {
dup2(fsrv->dev_null_fd, 1);
dup2(fsrv->dev_null_fd, 2);
@@ -253,7 +308,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
#ifndef HAVE_ARC4RANDOM
close(fsrv->dev_urandom_fd);
#endif
- close(fsrv->plot_file == NULL ? -1 : fileno(fsrv->plot_file));
+ if (fsrv->plot_file != NULL) fclose(fsrv->plot_file);
/* This should improve performance a bit, since it stops the linker from
doing extra work post-fork(). */
@@ -282,15 +337,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
"msan_track_origins=0",
0);
- if (fsrv->use_fauxsrv) {
-
- afl_fauxsrv_execv(fsrv, argv);
-
- } else {
-
- execv(fsrv->target_path, argv);
-
- }
+ fsrv->init_child_func(fsrv, argv);
/* Use a distinctive bitmap signature to tell the parent about execv()
falling through. */
@@ -315,18 +362,23 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
rlen = 0;
if (fsrv->exec_tmout) {
- rlen = 4;
- u32 time = read_timed(fsrv->fsrv_st_fd, &status, rlen,
- fsrv->exec_tmout * FORK_WAIT_MULT);
+ u32 time = read_timed(fsrv->fsrv_st_fd, &status, 4,
+ fsrv->exec_tmout * FORK_WAIT_MULT, stop_soon_p);
- if (time > fsrv->exec_tmout * FORK_WAIT_MULT) {
+ if (!time) {
- fsrv->child_timed_out = 1;
kill(fsrv->fsrv_pid, SIGKILL);
- }
+ } else if (time > fsrv->exec_tmout * FORK_WAIT_MULT) {
+
+ fsrv->last_run_timed_out = 1;
+ kill(fsrv->fsrv_pid, SIGKILL);
+
+ } else {
+
+ rlen = 4;
- if (!time) { kill(fsrv->fsrv_pid, SIGKILL); }
+ }
} else {
@@ -339,12 +391,113 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
if (rlen == 4) {
- if (!getenv("AFL_QUIET")) OKF("All right - fork server is up.");
+ if (!be_quiet) OKF("All right - fork server is up.");
+
+ if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
+
+ if (!be_quiet && getenv("AFL_DEBUG"))
+ ACTF("Extended forkserver functions received (%08x).", status);
+
+ if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
+
+ fsrv->snapshot = 1;
+ if (!be_quiet) ACTF("Using SNAPSHOT feature.");
+
+ }
+
+ if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
+
+ u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
+
+ if (!fsrv->map_size) fsrv->map_size = MAP_SIZE;
+
+ if (unlikely(tmp_map_size % 8)) {
+
+ // should not happen
+ WARNF("Target reported non-aligned map size of %ud", tmp_map_size);
+ tmp_map_size = (((tmp_map_size + 8) >> 3) << 3);
+
+ }
+
+ if (!be_quiet) ACTF("Target map size: %u", tmp_map_size);
+ if (tmp_map_size > fsrv->map_size)
+ FATAL(
+ "Target's coverage map size of %u is larger than the one this "
+ "afl++ is set with (%u) (change MAP_SIZE_POW2 in config.h and "
+ "recompile or set AFL_MAP_SIZE)\n",
+ tmp_map_size, fsrv->map_size);
+ fsrv->map_size = tmp_map_size;
+
+ }
+
+ if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
+
+ if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) {
+
+ // this is not afl-fuzz - we deny and return
+ status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT));
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
+ FATAL("Writing to forkserver failed.");
+ return;
+
+ }
+
+ if (!be_quiet) ACTF("Using AUTODICT feature.");
+ status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4)
+ FATAL("Writing to forkserver failed.");
+ if (read(fsrv->fsrv_st_fd, &status, 4) != 4)
+ FATAL("Reading from forkserver failed.");
+
+ if (status < 2 || (u32)status > 0xffffff)
+ FATAL("Dictionary has an illegal size: %d", status);
+
+ u32 len = status, offset = 0, count = 0;
+ u8 *dict = ck_alloc(len);
+ if (dict == NULL)
+ FATAL("Could not allocate %u bytes of autodictionary memory", len);
+
+ while (len != 0) {
+
+ rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
+ if (rlen > 0) {
+
+ len -= rlen;
+ offset += rlen;
+
+ } else {
+
+ FATAL(
+ "Reading autodictionary fail at position %u with %u bytes "
+ "left.",
+ offset, len);
+
+ }
+
+ }
+
+ offset = 0;
+ while (offset < status && (u8)dict[offset] + offset < status) {
+
+ fsrv->function_ptr(fsrv->function_opt, dict + offset + 1,
+ (u8)dict[offset]);
+ offset += (1 + dict[offset]);
+ count++;
+
+ }
+
+ if (!be_quiet) ACTF("Loaded %u autodictionary entries", count);
+ ck_free(dict);
+
+ }
+
+ }
+
return;
}
- 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");
@@ -496,11 +649,186 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv) {
}
+static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
+
+ if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL);
+ if (fsrv->fsrv_pid > 0) {
+
+ kill(fsrv->fsrv_pid, SIGKILL);
+ if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
+
+ }
+
+}
+
+/* Delete the current testcase and write the buf to the testcase file */
+
+void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
+
+ s32 fd = fsrv->out_fd;
+
+ if (fsrv->out_file) {
+
+ if (fsrv->no_unlink) {
+
+ fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+
+ } else {
+
+ unlink(fsrv->out_file); /* Ignore errors. */
+ fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
+
+ }
+
+ if (fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+
+ } else {
+
+ lseek(fd, 0, SEEK_SET);
+
+ }
+
+ ck_write(fd, buf, len, fsrv->out_file);
+
+ if (!fsrv->out_file) {
+
+ if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
+ lseek(fd, 0, SEEK_SET);
+
+ } else {
+
+ close(fd);
+
+ }
+
+}
+
+/* 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, u32 timeout,
+ volatile u8 *stop_soon_p) {
+
+ s32 res;
+ u32 exec_ms;
+
+ int status = 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
+ 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;
+
+ }
+
+ // Fauxserver should handle this now.
+ // if (tb4 == EXEC_FAIL_SIG) return FSRV_RUN_ERROR;
+
+ return FSRV_RUN_OK;
+
+}
+
void afl_fsrv_killall() {
LIST_FOREACH(&fsrv_list, afl_forkserver_t, {
- if (el->child_pid > 0) kill(el->child_pid, SIGKILL);
+ afl_fsrv_kill(el);
});
@@ -508,6 +836,7 @@ void afl_fsrv_killall() {
void afl_fsrv_deinit(afl_forkserver_t *fsrv) {
+ afl_fsrv_kill(fsrv);
list_remove(&fsrv_list, fsrv);
}
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index c5347dcb..0823deed 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -43,21 +43,7 @@ void write_bitmap(afl_state_t *afl) {
if (fd < 0) PFATAL("Unable to open '%s'", fname);
- ck_write(fd, afl->virgin_bits, MAP_SIZE, fname);
-
- close(fd);
-
-}
-
-/* Read bitmap from file. This is for the -B option again. */
-
-void read_bitmap(afl_state_t *afl, u8 *fname) {
-
- s32 fd = open(fname, O_RDONLY);
-
- if (fd < 0) PFATAL("Unable to open '%s'", fname);
-
- ck_read(fd, afl->virgin_bits, MAP_SIZE, fname);
+ ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname);
close(fd);
@@ -78,16 +64,18 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
u64 *current = (u64 *)afl->fsrv.trace_bits;
u64 *virgin = (u64 *)virgin_map;
- u32 i = (MAP_SIZE >> 3);
+ u32 i = (afl->fsrv.map_size >> 3);
#else
u32 *current = (u32 *)afl->fsrv.trace_bits;
u32 *virgin = (u32 *)virgin_map;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (afl->fsrv.map_size >> 2);
#endif /* ^WORD_SIZE_64 */
+ // the map size must be a minimum of 8 bytes.
+ // for variable/dynamic map sizes this is ensured in the forkserver
u8 ret = 0;
@@ -97,6 +85,7 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
that have not been already cleared from the virgin map - since this will
almost always be the case. */
+ // the (*current) is unnecessary but speeds up the overall comparison
if (unlikely(*current) && unlikely(*current & *virgin)) {
if (likely(ret < 2)) {
@@ -109,18 +98,20 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
#ifdef WORD_SIZE_64
- if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
- (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) ||
- (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) ||
- (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff))
+ if (*virgin == 0xffffffffffffffff || (cur[0] && vir[0] == 0xff) ||
+ (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) ||
+ (cur[3] && vir[3] == 0xff) || (cur[4] && vir[4] == 0xff) ||
+ (cur[5] && vir[5] == 0xff) || (cur[6] && vir[6] == 0xff) ||
+ (cur[7] && vir[7] == 0xff))
ret = 2;
else
ret = 1;
#else
- if ((cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) ||
- (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff))
+ if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) ||
+ (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) ||
+ (cur[3] && vir[3] == 0xff))
ret = 2;
else
ret = 1;
@@ -138,7 +129,7 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
}
- if (unlikely(ret) && unlikely(virgin_map == afl->virgin_bits))
+ if (unlikely(ret) && likely(virgin_map == afl->virgin_bits))
afl->bitmap_changed = 1;
return ret;
@@ -148,10 +139,10 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) {
/* Count the number of bits set in the provided bitmap. Used for the status
screen several times every second, does not have to be fast. */
-u32 count_bits(u8 *mem) {
+u32 count_bits(afl_state_t *afl, u8 *mem) {
u32 *ptr = (u32 *)mem;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (afl->fsrv.map_size >> 2);
u32 ret = 0;
while (i--) {
@@ -182,10 +173,10 @@ u32 count_bits(u8 *mem) {
mostly to update the status screen or calibrate and examine confirmed
new paths. */
-u32 count_bytes(u8 *mem) {
+u32 count_bytes(afl_state_t *afl, u8 *mem) {
u32 *ptr = (u32 *)mem;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (afl->fsrv.map_size >> 2);
u32 ret = 0;
while (i--) {
@@ -207,10 +198,10 @@ u32 count_bytes(u8 *mem) {
/* Count the number of non-255 bytes set in the bitmap. Used strictly for the
status screen, several calls per second or so. */
-u32 count_non_255_bytes(u8 *mem) {
+u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) {
u32 *ptr = (u32 *)mem;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (afl->fsrv.map_size >> 2);
u32 ret = 0;
while (i--) {
@@ -245,9 +236,9 @@ const u8 simplify_lookup[256] = {
#ifdef WORD_SIZE_64
-void simplify_trace(u64 *mem) {
+void simplify_trace(afl_state_t *afl, u64 *mem) {
- u32 i = MAP_SIZE >> 3;
+ u32 i = (afl->fsrv.map_size >> 3);
while (i--) {
@@ -278,9 +269,9 @@ void simplify_trace(u64 *mem) {
#else
-void simplify_trace(u32 *mem) {
+void simplify_trace(afl_state_t *afl, u32 *mem) {
- u32 i = MAP_SIZE >> 2;
+ u32 i = (afl->fsrv.map_size >> 2);
while (i--) {
@@ -340,9 +331,11 @@ void init_count_class16(void) {
#ifdef WORD_SIZE_64
-void classify_counts(u64 *mem) {
+void classify_counts(afl_forkserver_t *fsrv) {
+
+ u64 *mem = (u64 *)fsrv->trace_bits;
- u32 i = MAP_SIZE >> 3;
+ u32 i = (fsrv->map_size >> 3);
while (i--) {
@@ -367,9 +360,11 @@ void classify_counts(u64 *mem) {
#else
-void classify_counts(u32 *mem) {
+void classify_counts(afl_forkserver_t *fsrv) {
+
+ u32 *mem = (u32 *)fsrv->trace_bits;
- u32 i = MAP_SIZE >> 2;
+ u32 i = (fsrv->map_size >> 2);
while (i--) {
@@ -396,11 +391,11 @@ void classify_counts(u32 *mem) {
count information here. This is called only sporadically, for some
new paths. */
-void minimize_bits(u8 *dst, u8 *src) {
+void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
u32 i = 0;
- while (i < MAP_SIZE) {
+ while (i < afl->fsrv.map_size) {
if (*(src++)) dst[i >> 3] |= 1 << (i & 7);
++i;
@@ -520,14 +515,14 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(len == 0)) return 0;
u8 *queue_fn = "";
- u8 hnb;
+ u8 hnb = '\0';
s32 fd;
u8 keeping = 0, res;
u8 fn[PATH_MAX];
/* Update path frequency. */
- u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
struct queue_entry *q = afl->queue;
while (q) {
@@ -583,7 +578,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);
@@ -597,7 +592,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
@@ -611,9 +606,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->dumb_mode)) {
#ifdef WORD_SIZE_64
- simplify_trace((u64 *)afl->fsrv.trace_bits);
+ simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);
#else
- simplify_trace((u32 *)afl->fsrv.trace_bits);
+ simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
#endif /* ^WORD_SIZE_64 */
if (!has_new_bits(afl, afl->virgin_tmout)) return keeping;
@@ -630,15 +625,15 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
u8 new_fault;
write_to_testcase(afl, mem, len);
- new_fault = run_target(afl, afl->hang_tmout);
+ new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout);
/* A corner case that one user reported bumping into: increasing the
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;
}
@@ -660,7 +655,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:
@@ -675,9 +670,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->dumb_mode)) {
#ifdef WORD_SIZE_64
- simplify_trace((u64 *)afl->fsrv.trace_bits);
+ simplify_trace(afl, (u64 *)afl->fsrv.trace_bits);
#else
- simplify_trace((u32 *)afl->fsrv.trace_bits);
+ simplify_trace(afl, (u32 *)afl->fsrv.trace_bits);
#endif /* ^WORD_SIZE_64 */
if (!has_new_bits(afl, afl->virgin_crash)) return keeping;
@@ -689,7 +684,8 @@ 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
@@ -703,9 +699,11 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
// if the user wants to be informed on new crashes - do that
#if !TARGET_OS_IPHONE
- if (system(afl->infoexec) == -1)
- hnb += 0; // we dont care if system errors, but we dont want a
- // compiler warning either
+ // we dont care if system errors, but we dont want a
+ // compiler warning either
+ // See
+ // https://stackoverflow.com/questions/11888594/ignoring-return-values-in-c
+ (void)(system(afl->infoexec) + 1);
#else
WARNF("command execution unsupported");
#endif
@@ -713,11 +711,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 f932f33b..12c814ba 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -29,478 +29,18 @@
#include "afl-fuzz.h"
#include "cmplog.h"
-void init_cmplog_forkserver(afl_state_t *afl) {
+typedef struct cmplog_data {
- int st_pipe[2], ctl_pipe[2];
- int status;
- s32 rlen;
+} cmplog_data_t;
- ACTF("Spinning up the cmplog fork server...");
+void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
- if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed");
+ setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
- afl->fsrv.child_timed_out = 0;
- afl->cmplog_fsrv_pid = fork();
+ if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary)
+ argv[0] = fsrv->cmplog_binary;
- if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed");
-
- if (!afl->cmplog_fsrv_pid) {
-
- /* CHILD PROCESS */
-
- struct rlimit r;
-
- /* Umpf. On OpenBSD, the default fd limit for root users is set to
- soft 128. Let's try to fix that... */
-
- if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
-
- r.rlim_cur = FORKSRV_FD + 2;
- setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */
-
- }
-
- if (afl->fsrv.mem_limit) {
-
- r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20;
-
-#ifdef RLIMIT_AS
- setrlimit(RLIMIT_AS, &r); /* Ignore errors */
-#else
- /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but
- according to reliable sources, RLIMIT_DATA covers anonymous
- maps - so we should be getting good protection against OOM bugs. */
-
- setrlimit(RLIMIT_DATA, &r); /* Ignore errors */
-#endif /* ^RLIMIT_AS */
-
- }
-
- /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered
- before the dump is complete. */
-
- // r.rlim_max = r.rlim_cur = 0;
- // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */
-
- /* Isolate the process and configure standard descriptors. If
- afl->fsrv.out_file is specified, stdin is /dev/null; otherwise,
- afl->fsrv.out_fd is cloned instead. */
-
- setsid();
-
- if (!(afl->afl_env.afl_debug_child_output)) {
-
- dup2(afl->fsrv.dev_null_fd, 1);
- dup2(afl->fsrv.dev_null_fd, 2);
-
- }
-
- if (!afl->fsrv.use_stdin) {
-
- dup2(afl->fsrv.dev_null_fd, 0);
-
- } else {
-
- dup2(afl->fsrv.out_fd, 0);
- close(afl->fsrv.out_fd);
-
- }
-
- /* Set up control and status pipes, close the unneeded original fds. */
-
- if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed");
- if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed");
-
- close(ctl_pipe[0]);
- close(ctl_pipe[1]);
- close(st_pipe[0]);
- close(st_pipe[1]);
-
- close(afl->fsrv.out_dir_fd);
- close(afl->fsrv.dev_null_fd);
-#ifndef HAVE_ARC4RANDOM
- close(afl->fsrv.dev_urandom_fd);
-#endif
- close(afl->fsrv.plot_file == NULL ? -1 : fileno(afl->fsrv.plot_file));
-
- /* This should improve performance a bit, since it stops the linker from
- doing extra work post-fork(). */
-
- if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0);
-
- /* Set sane defaults for ASAN if nothing else specified. */
-
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "malloc_context_size=0:"
- "symbolize=0:"
- "allocator_may_return_null=1",
- 0);
-
- /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
- point. So, we do this in a very hacky way. */
-
- setenv("MSAN_OPTIONS",
- "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "symbolize=0:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "msan_track_origins=0",
- 0);
-
- setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
-
- if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) {
-
- ck_free(afl->argv[0]);
- afl->argv[0] = afl->cmplog_binary;
-
- }
-
- execv(afl->argv[0], afl->argv);
-
- /* Use a distinctive bitmap signature to tell the parent about execv()
- falling through. */
-
- *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG;
- exit(0);
-
- }
-
- /* PARENT PROCESS */
-
- /* Close the unneeded endpoints. */
-
- close(ctl_pipe[0]);
- close(st_pipe[1]);
-
- afl->cmplog_fsrv_ctl_fd = ctl_pipe[1];
- afl->cmplog_fsrv_st_fd = st_pipe[0];
-
- /* Wait for the fork server to come up, but don't wait too long. */
-
- rlen = 0;
- if (afl->fsrv.exec_tmout) {
-
- rlen = 4;
- u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT;
- /* Reuse readfds as exceptfds to see when the child closed the pipe */
- u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms);
-
- if (!exec_ms) {
-
- PFATAL("Error in timed read");
-
- } else if (exec_ms > timeout_ms) {
-
- afl->fsrv.child_timed_out = 1;
- kill(afl->cmplog_fsrv_pid, SIGKILL);
- rlen = read(afl->cmplog_fsrv_st_fd, &status, 4);
-
- }
-
- } else {
-
- rlen = read(afl->cmplog_fsrv_st_fd, &status, 4);
-
- }
-
- /* If we have a four-byte "hello" message from the server, we're all set.
- Otherwise, try to figure out what went wrong. */
-
- if (afl->fsrv.child_timed_out)
- FATAL(
- "Timeout while initializing cmplog fork server (adjusting -t may "
- "help)");
-
- if (rlen == 4) {
-
- OKF("All right - fork server is up.");
- return;
-
- }
-
- if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0)
- PFATAL("waitpid() failed");
-
- if (WIFSIGNALED(status)) {
-
- if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 &&
- afl->fsrv.uses_asan) {
-
- SAYF("\n" cLRD "[-] " cRST
- "Whoops, the target binary crashed suddenly, "
- "before receiving any input\n"
- " from the fuzzer! Since it seems to be built with ASAN and you "
- "have a\n"
- " restrictive memory limit configured, this is expected; please "
- "read\n"
- " %s/notes_for_asan.md for help.\n",
- doc_path);
-
- } else if (!afl->fsrv.mem_limit) {
-
- SAYF("\n" cLRD "[-] " cRST
- "Whoops, the target binary crashed suddenly, "
- "before receiving any input\n"
- " from the fuzzer! There are several probable explanations:\n\n"
-
- " - The binary is just buggy and explodes entirely on its own. "
- "If so, you\n"
- " need to fix the underlying problem or find a better "
- "replacement.\n\n"
-
- MSG_FORK_ON_APPLE
-
- " - Less likely, there is a horrible bug in the fuzzer. If other "
- "options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
- "tips.\n");
-
- } else {
-
- u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
-
- SAYF("\n" cLRD "[-] " cRST
- "Whoops, the target binary crashed suddenly, "
- "before receiving any input\n"
- " from the fuzzer! There are several probable explanations:\n\n"
-
- " - The current memory limit (%s) is too restrictive, causing "
- "the\n"
- " target to hit an OOM condition in the dynamic linker. Try "
- "bumping up\n"
- " the limit with the -m setting in the command line. A simple "
- "way confirm\n"
- " this diagnosis would be:\n\n"
-
- MSG_ULIMIT_USAGE
- " /path/to/fuzzed_app )\n\n"
-
- " Tip: you can use http://jwilk.net/software/recidivm to "
- "quickly\n"
- " estimate the required amount of virtual memory for the "
- "binary.\n\n"
-
- " - The binary is just buggy and explodes entirely on its own. "
- "If so, you\n"
- " need to fix the underlying problem or find a better "
- "replacement.\n\n"
-
- MSG_FORK_ON_APPLE
-
- " - Less likely, there is a horrible bug in the fuzzer. If other "
- "options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
- "tips.\n",
- stringify_mem_size(val_buf, sizeof(val_buf),
- afl->fsrv.mem_limit << 20),
- afl->fsrv.mem_limit - 1);
-
- }
-
- FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status));
-
- }
-
- if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG)
- FATAL("Unable to execute target application ('%s')", afl->argv[0]);
-
- if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) {
-
- SAYF("\n" cLRD "[-] " cRST
- "Hmm, looks like the target binary terminated "
- "before we could complete a\n"
- " handshake with the injected code. Since it seems to be built "
- "with ASAN and\n"
- " you have a restrictive memory limit configured, this is "
- "expected; please\n"
- " read %s/notes_for_asan.md for help.\n",
- doc_path);
-
- } else if (!afl->fsrv.mem_limit) {
-
- SAYF("\n" cLRD "[-] " cRST
- "Hmm, looks like the target binary terminated "
- "before we could complete a\n"
- " handshake with the injected code. Perhaps there is a horrible "
- "bug in the\n"
- " fuzzer. Poke <afl-users@googlegroups.com> for troubleshooting "
- "tips.\n");
-
- } else {
-
- u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
-
- SAYF(
- "\n" cLRD "[-] " cRST
- "Hmm, looks like the target binary terminated "
- "before we could complete a\n"
- " handshake with the injected code. There are %s probable "
- "explanations:\n\n"
-
- "%s"
- " - The current memory limit (%s) is too restrictive, causing an "
- "OOM\n"
- " fault in the dynamic linker. This can be fixed with the -m "
- "option. A\n"
- " simple way to confirm the diagnosis may be:\n\n"
-
- MSG_ULIMIT_USAGE
- " /path/to/fuzzed_app )\n\n"
-
- " Tip: you can use http://jwilk.net/software/recidivm to quickly\n"
- " estimate the required amount of virtual memory for the "
- "binary.\n\n"
-
- " - Less likely, there is a horrible bug in the fuzzer. If other "
- "options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
- "tips.\n",
- getenv(DEFER_ENV_VAR) ? "three" : "two",
- getenv(DEFER_ENV_VAR)
- ? " - You are using deferred forkserver, but __AFL_INIT() is "
- "never\n"
- " reached before the program terminates.\n\n"
- : "",
- stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20),
- afl->fsrv.mem_limit - 1);
-
- }
-
- FATAL("Cmplog fork server handshake failed");
-
-}
-
-u8 run_cmplog_target(afl_state_t *afl, u32 timeout) {
-
- int status = 0;
- u32 exec_ms;
-
- u32 tb4;
- s32 res;
-
- afl->fsrv.child_timed_out = 0;
-
- /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we
- must prevent any earlier operations from venturing into that
- territory. */
-
- memset(afl->fsrv.trace_bits, 0, MAP_SIZE);
- MEM_BARRIER();
-
- /* Since we always have a forkserver (or a fauxserver) running, we can simply
- tell them to have at it and read back the pid from it.*/
-
- if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) !=
- 4) {
-
- if (afl->stop_soon) return 0;
- RPFATAL(res,
- "Unable to request new process from cmplog fork server (OOM?)");
-
- }
-
- if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) {
-
- if (afl->stop_soon) return 0;
- RPFATAL(res,
- "Unable to request new process from cmplog fork server (OOM?)");
-
- }
-
- if (afl->cmplog_child_pid <= 0)
- FATAL("Cmplog fork server is misbehaving (OOM?)");
-
- /* Configure timeout, as requested by user, then wait for child to terminate.
- */
- exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout);
-
- 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(afl->cmplog_child_pid, SIGKILL);
- afl->fsrv.child_timed_out = 1;
-
- /* After killing the child, the forkserver should tell us */
- if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0;
-
- }
-
- if (!exec_ms) { // Something went wrong.
-
- 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\n"
- "If all else fails you can disable the fork server via "
- "AFL_NO_FORKSRV=1.\n",
- afl->fsrv.mem_limit);
- RPFATAL(res, "Unable to communicate with fork server");
-
- }
-
- if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0;
-
- if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms;
-
- ++afl->total_execs;
-
- /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the
- compiler below this point. Past this location, afl->fsrv.trace_bits[]
- behave very normally and do not have to be treated as volatile. */
-
- MEM_BARRIER();
-
- tb4 = *(u32 *)afl->fsrv.trace_bits;
-
-#ifdef WORD_SIZE_64
- classify_counts((u64 *)afl->fsrv.trace_bits);
-#else
- classify_counts((u32 *)afl->fsrv.trace_bits);
-#endif /* ^WORD_SIZE_64 */
-
- afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out;
-
- /* Report outcome to caller. */
-
- if (WIFSIGNALED(status) && !afl->stop_soon) {
-
- afl->kill_signal = WTERMSIG(status);
-
- if (afl->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 (afl->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;
+ execv(argv[0], argv);
}
@@ -522,11 +62,11 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
write_to_testcase(afl, out_buf, len);
- fault = run_cmplog_target(afl, afl->fsrv.exec_tmout);
+ fault = fuzz_run_target(afl, &afl->cmplog_fsrv, afl->fsrv.exec_tmout);
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-extras.c b/src/afl-fuzz-extras.c
index 16806934..c366cc5b 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -130,6 +130,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
+ if (!wptr) PFATAL("no mem for data");
+
while (*lptr) {
char *hexdigits = "0123456789abcdef";
@@ -305,10 +307,14 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) {
}
/* Maybe add automatic extra. */
+/* Ugly hack: afl state is transfered as u8* because we import data via
+ afl-forkserver.c - which is shared with other afl tools that do not
+ have the afl state struct */
-void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) {
+void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) {
- u32 i;
+ afl_state_t *afl = (afl_state_t *)afl_tmp;
+ u32 i;
/* Allow users to specify that they don't want auto dictionaries. */
@@ -469,7 +475,7 @@ void load_auto(afl_state_t *afl) {
if (len < 0) PFATAL("Unable to read from '%s'", fn);
if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA)
- maybe_add_auto(afl, tmp, len);
+ maybe_add_auto((u8 *)afl, tmp, len);
close(fd);
ck_free(fn);
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index efdde463..3da348d2 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -134,8 +134,15 @@ void bind_to_free_cpu(afl_state_t *afl) {
for (i = 0; i < proccount; i++) {
#if defined(__FreeBSD__)
- if (procs[i].ki_oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
- cpu_used[procs[i].ki_oncpu] = 1;
+ if (!strcmp(procs[i].ki_comm, "idle")) continue;
+
+ // fix when ki_oncpu = -1
+ int oncpu;
+ oncpu = procs[i].ki_oncpu;
+ if (oncpu == -1) oncpu = procs[i].ki_lastcpu;
+
+ if (oncpu != -1 && oncpu < sizeof(cpu_used) && procs[i].ki_pctcpu > 60)
+ cpu_used[oncpu] = 1;
#elif defined(__DragonFly__)
if (procs[i].kp_lwp.kl_cpuid < sizeof(cpu_used) &&
procs[i].kp_lwp.kl_pctcpu > 10)
@@ -435,21 +442,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->fsrv.trace_bits) < 100) return;
-
- for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i)
- if (afl->fsrv.trace_bits[i]) 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. */
@@ -484,21 +476,19 @@ 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:
-
- if (q == afl->queue) check_map_coverage(afl);
+ case FSRV_RUN_OK:
if (afl->crash_mode) FATAL("Test case '%s' does *NOT* crash", fn);
break;
- case FAULT_TMOUT:
+ case FSRV_RUN_TMOUT:
if (afl->timeout_given) {
@@ -547,7 +537,7 @@ void perform_dry_run(afl_state_t *afl) {
}
- case FAULT_CRASH:
+ case FSRV_RUN_CRASH:
if (afl->crash_mode) break;
@@ -641,13 +631,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;
@@ -1410,6 +1400,8 @@ void setup_dirs_fds(afl_state_t *afl) {
"# 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 */
}
@@ -1844,8 +1836,6 @@ static void handle_stop_sig(int sig) {
if (el->fsrv.child_pid > 0) kill(el->fsrv.child_pid, SIGKILL);
if (el->fsrv.fsrv_pid > 0) kill(el->fsrv.fsrv_pid, SIGKILL);
- if (el->cmplog_child_pid > 0) kill(el->cmplog_child_pid, SIGKILL);
- if (el->cmplog_fsrv_pid > 0) kill(el->cmplog_fsrv_pid, SIGKILL);
});
@@ -1979,7 +1969,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
#endif /* ^!__APPLE__ */
- if (!afl->qemu_mode && !afl->unicorn_mode && !afl->dumb_mode &&
+ if (!afl->fsrv.qemu_mode && !afl->unicorn_mode && !afl->dumb_mode &&
!memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
@@ -2006,7 +1996,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
- if ((afl->qemu_mode) &&
+ if ((afl->fsrv.qemu_mode) &&
memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
@@ -2171,6 +2161,8 @@ void save_cmdline(afl_state_t *afl, u32 argc, char **argv) {
u32 l = strlen(argv[i]);
+ if (!argv[i] || !buf) FATAL("null deref detected");
+
memcpy(buf, argv[i], l);
buf += l;
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 754b2190..434b4673 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -27,14 +27,11 @@
#include "afl-fuzz.h"
void load_custom_mutator(afl_state_t *, const char *);
-#ifdef USE_PYTHON
-void load_custom_mutator_py(afl_state_t *, char *);
-#endif
void setup_custom_mutator(afl_state_t *afl) {
/* Try mutator library first */
- u8 *fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
+ u8 *fn = afl->afl_env.afl_custom_mutator_library;
if (fn) {
@@ -52,7 +49,7 @@ void setup_custom_mutator(afl_state_t *afl) {
/* Try Python module */
#ifdef USE_PYTHON
- u8 *module_name = getenv("AFL_PYTHON_MODULE");
+ u8 *module_name = afl->afl_env.afl_python_module;
if (module_name) {
@@ -67,7 +64,7 @@ void setup_custom_mutator(afl_state_t *afl) {
}
#else
- if (getenv("AFL_PYTHON_MODULE"))
+ if (afl->afl_env.afl_python_module)
FATAL("Your AFL binary was built without Python support");
#endif
@@ -239,12 +236,12 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
write_to_testcase(afl, retbuf, retlen);
- fault = run_target(afl, afl->fsrv.exec_tmout);
+ fault = fuzz_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, MAP_SIZE, HASH_CONST);
+ cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (cksum == q->exec_cksum) {
@@ -257,7 +254,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
if (!needs_write) {
needs_write = 1;
- memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, MAP_SIZE);
+ memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits,
+ afl->fsrv.map_size);
}
@@ -307,7 +305,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
ck_write(fd, in_buf, q->len, q->fname);
close(fd);
- memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, MAP_SIZE);
+ memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size);
update_bitmap_score(afl, q);
}
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index b20bde90..a4ba739e 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -27,7 +27,7 @@
/* MOpt */
-int select_algorithm(afl_state_t *afl) {
+static int select_algorithm(afl_state_t *afl) {
int i_puppet, j_puppet;
@@ -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)) {
@@ -501,7 +501,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
if (unlikely(afl->use_radamsa > 1)) goto radamsa_stage;
- if (afl->shm.cmplog_mode) {
+ if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
if (input_to_state_stage(afl, in_buf, out_buf, len,
afl->queue_cur->exec_cksum))
@@ -601,7 +601,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) {
- u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
@@ -613,7 +613,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
++a_len;
if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
- maybe_add_auto(afl, a_collect, a_len);
+ maybe_add_auto((u8 *)afl, a_collect, a_len);
} else if (cksum != prev_cksum) {
@@ -621,7 +621,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
worthwhile queued up, and collect that if the answer is yes. */
if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
- maybe_add_auto(afl, a_collect, a_len);
+ maybe_add_auto((u8 *)afl, a_collect, a_len);
a_len = 0;
prev_cksum = cksum;
@@ -761,7 +761,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
without wasting time on checksums. */
if (!afl->dumb_mode && len >= EFF_MIN_LEN)
- cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
else
cksum = ~afl->queue_cur->exec_cksum;
@@ -2366,7 +2366,7 @@ abandon_entry:
}
/* MOpt mode */
-u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
+static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
if (!MOpt_globals.is_pilot_mode) {
@@ -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) {
@@ -2522,20 +2522,15 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
orig_perf = perf_score = calculate_score(afl, afl->queue_cur);
- /* Skip right away if -d is given, if we have done deterministic fuzzing on
- this entry ourselves (was_fuzzed), or if it has gone through deterministic
- testing in earlier, resumed runs (passed_det). */
+ if (afl->shm.cmplog_mode && !afl->queue_cur->fully_colorized) {
- if (afl->skip_deterministic || afl->queue_cur->was_fuzzed ||
- afl->queue_cur->passed_det)
- goto havoc_stage;
+ if (input_to_state_stage(afl, in_buf, out_buf, len,
+ afl->queue_cur->exec_cksum))
+ goto abandon_entry;
- /* Skip deterministic fuzzing if exec path checksum puts this out of scope
- for this master instance. */
+ }
- if (afl->master_max &&
- (afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1)
- goto havoc_stage;
+ /* Go to pacemker fuzzing if MOpt is doing well */
cur_ms_lv = get_cur_time();
if (!(afl->key_puppet == 0 &&
@@ -2549,6 +2544,21 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
}
+ /* Skip right away if -d is given, if we have done deterministic fuzzing on
+ this entry ourselves (was_fuzzed), or if it has gone through deterministic
+ testing in earlier, resumed runs (passed_det). */
+
+ if (afl->skip_deterministic || afl->queue_cur->was_fuzzed ||
+ afl->queue_cur->passed_det)
+ goto havoc_stage;
+
+ /* Skip deterministic fuzzing if exec path checksum puts this out of scope
+ for this master instance. */
+
+ if (afl->master_max &&
+ (afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1)
+ goto havoc_stage;
+
doing_det = 1;
/*********************************************
@@ -2615,7 +2625,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) {
- u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) {
@@ -2627,7 +2637,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
++a_len;
if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
- maybe_add_auto(afl, a_collect, a_len);
+ maybe_add_auto((u8 *)afl, a_collect, a_len);
} else if (cksum != prev_cksum) {
@@ -2635,7 +2645,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
worthwhile queued up, and collect that if the answer is yes. */
if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA)
- maybe_add_auto(afl, a_collect, a_len);
+ maybe_add_auto((u8 *)afl, a_collect, a_len);
a_len = 0;
prev_cksum = cksum;
@@ -2775,7 +2785,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
without wasting time on checksums. */
if (!afl->dumb_mode && len >= EFF_MIN_LEN)
- cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
else
cksum = ~afl->queue_cur->exec_cksum;
@@ -3593,7 +3603,6 @@ pacemaker_fuzzing:
}
s32 temp_len_puppet;
- cur_ms_lv = get_cur_time();
// for (; afl->swarm_now < swarm_num; ++afl->swarm_now)
{
@@ -4167,8 +4176,6 @@ pacemaker_fuzzing:
afl->orig_hit_cnt_puppet))) {
afl->key_puppet = 0;
- cur_ms_lv = get_cur_time();
- new_hit_cnt = afl->queued_paths + afl->unique_crashes;
afl->orig_hit_cnt_puppet = 0;
afl->last_limit_time_start = 0;
@@ -4377,7 +4384,7 @@ void pso_updating(afl_state_t *afl) {
u8 fuzz_one(afl_state_t *afl) {
- int key_val_lv = 0;
+ int key_val_lv_1 = 0, key_val_lv_2 = 0;
#ifdef _AFL_DOCUMENT_MUTATIONS
@@ -4397,22 +4404,22 @@ u8 fuzz_one(afl_state_t *afl) {
#endif
- if (afl->limit_time_sig == 0) {
+ // if limit_time_sig == -1 then both are run after each other
- key_val_lv = fuzz_one_original(afl);
+ if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); }
- } else {
+ if (afl->limit_time_sig != 0) {
if (afl->key_module == 0)
- key_val_lv = pilot_fuzzing(afl);
+ key_val_lv_2 = pilot_fuzzing(afl);
else if (afl->key_module == 1)
- key_val_lv = core_fuzzing(afl);
+ key_val_lv_2 = core_fuzzing(afl);
else if (afl->key_module == 2)
pso_updating(afl);
}
- return key_val_lv;
+ return (key_val_lv_1 | key_val_lv_2);
#undef BUF_PARAMS
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 12c3a09d..d4519c6d 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -41,8 +41,8 @@ it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */
(void **)&((py_mutator_t *)py_mutator)->name##_buf, \
&((py_mutator_t *)py_mutator)->name##_size
-size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
- u8 *add_buf, size_t add_buf_size, size_t max_size) {
+static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf,
+ u8 *add_buf, size_t add_buf_size, size_t max_size) {
size_t mutated_size;
PyObject *py_args, *py_value;
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 174d7d92..121eb3f1 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -195,7 +195,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
/* For every byte set in afl->fsrv.trace_bits[], see if there is a previous
winner, and how it compares to us. */
- for (i = 0; i < MAP_SIZE; ++i)
+ for (i = 0; i < afl->fsrv.map_size; ++i)
if (afl->fsrv.trace_bits[i]) {
@@ -248,8 +248,9 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
if (!q->trace_mini) {
- q->trace_mini = ck_alloc(MAP_SIZE >> 3);
- minimize_bits(q->trace_mini, afl->fsrv.trace_bits);
+ u32 len = (afl->fsrv.map_size >> 3);
+ q->trace_mini = ck_alloc(len);
+ minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits);
}
@@ -268,14 +269,15 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
void cull_queue(afl_state_t *afl) {
struct queue_entry *q;
- u8 temp_v[MAP_SIZE >> 3];
+ u32 len = (afl->fsrv.map_size >> 3);
u32 i;
+ u8 * temp_v = afl->map_tmp_buf;
if (afl->dumb_mode || !afl->score_changed) return;
afl->score_changed = 0;
- memset(temp_v, 255, MAP_SIZE >> 3);
+ memset(temp_v, 255, len);
afl->queued_favored = 0;
afl->pending_favored = 0;
@@ -292,10 +294,10 @@ void cull_queue(afl_state_t *afl) {
/* Let's see if anything in the bitmap isn't captured in temp_v.
If yes, and if it has a afl->top_rated[] contender, let's use it. */
- for (i = 0; i < MAP_SIZE; ++i)
+ for (i = 0; i < afl->fsrv.map_size; ++i)
if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {
- u32 j = MAP_SIZE >> 3;
+ u32 j = len;
/* Remove all bits belonging to the current entry from temp_v. */
@@ -433,6 +435,8 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
}
+ if (unlikely(!n_paths)) FATAL("Queue state corrupt");
+
fuzz_mu = fuzz_total / n_paths;
if (fuzz <= fuzz_mu) {
@@ -485,7 +489,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 4acc204b..3e9af088 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -37,7 +37,7 @@ struct range {
};
-struct range *add_range(struct range *ranges, u32 start, u32 end) {
+static struct range *add_range(struct range *ranges, u32 start, u32 end) {
struct range *r = ck_alloc_nozero(sizeof(struct range));
r->start = start;
@@ -47,7 +47,7 @@ struct range *add_range(struct range *ranges, u32 start, u32 end) {
}
-struct range *pop_biggest_range(struct range **ranges) {
+static struct range *pop_biggest_range(struct range **ranges) {
struct range *r = *ranges;
struct range *prev = NULL;
@@ -88,7 +88,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u32 *cksum) {
if (unlikely(common_fuzz_stuff(afl, buf, len))) return 1;
- *cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ *cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
return 0;
}
@@ -115,32 +115,46 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
afl->stage_short = "colorization";
afl->stage_max = 1000;
- struct range *rng;
+ struct range *rng = NULL;
afl->stage_cur = 0;
while ((rng = pop_biggest_range(&ranges)) != NULL &&
afl->stage_cur < afl->stage_max) {
u32 s = rng->end - rng->start;
- if (s == 0) goto empty_range;
- memcpy(backup, buf + rng->start, s);
- rand_replace(afl, buf + rng->start, s);
+ if (s != 0) {
- u32 cksum;
- if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) goto checksum_fail;
+ /* Range not empty */
- if (cksum != exec_cksum) {
+ memcpy(backup, buf + rng->start, s);
+ rand_replace(afl, buf + rng->start, s);
- ranges = add_range(ranges, rng->start, rng->start + s / 2);
- ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
- memcpy(buf + rng->start, backup, s);
+ u32 cksum;
+ u64 start_us = get_cur_time_us();
+ if (unlikely(get_exec_checksum(afl, buf, len, &cksum)))
+ goto checksum_fail;
- } else
+ u64 stop_us = get_cur_time_us();
- needs_write = 1;
+ /* Discard if the mutations change the paths or if it is too decremental
+ in speed */
+ if (cksum != exec_cksum ||
+ (stop_us - start_us > 2 * afl->queue_cur->exec_us)) {
+
+ ranges = add_range(ranges, rng->start, rng->start + s / 2);
+ ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end);
+ memcpy(buf + rng->start, backup, s);
+
+ } else {
+
+ needs_write = 1;
+
+ }
+
+ }
- empty_range:
ck_free(rng);
+ rng = NULL;
++afl->stage_cur;
}
@@ -157,6 +171,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
rng = ranges;
ranges = ranges->next;
ck_free(rng);
+ rng = NULL;
}
@@ -189,6 +204,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) {
return 0;
checksum_fail:
+ if (rng) ck_free(rng);
ck_free(backup);
while (ranges) {
@@ -196,9 +212,12 @@ checksum_fail:
rng = ranges;
ranges = ranges->next;
ck_free(rng);
+ rng = NULL;
}
+ // TODO: clang notices a _potential_ leak of mem pointed to by rng
+
return 1;
}
@@ -225,24 +244,25 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
- u64 pattern, u64 repl, u32 idx, u8 *orig_buf,
- u8 *buf, u32 len, u8 do_reverse, u8 *status) {
+ u64 pattern, u64 repl, u64 o_pattern, u32 idx,
+ u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse,
+ u8 *status) {
u64 *buf_64 = (u64 *)&buf[idx];
u32 *buf_32 = (u32 *)&buf[idx];
u16 *buf_16 = (u16 *)&buf[idx];
- // u8* buf_8 = &buf[idx];
- // u64* o_buf_64 = (u64*)&orig_buf[idx];
- // u32* o_buf_32 = (u32*)&orig_buf[idx];
- // u16* o_buf_16 = (u16*)&orig_buf[idx];
- // u8* o_buf_8 = &orig_buf[idx];
+ u8 * buf_8 = &buf[idx];
+ u64 *o_buf_64 = (u64 *)&orig_buf[idx];
+ u32 *o_buf_32 = (u32 *)&orig_buf[idx];
+ u16 *o_buf_16 = (u16 *)&orig_buf[idx];
+ u8 * o_buf_8 = &orig_buf[idx];
u32 its_len = len - idx;
*status = 0;
if (SHAPE_BYTES(h->shape) == 8) {
- if (its_len >= 8 && *buf_64 == pattern) { // && *o_buf_64 == pattern) {
+ if (its_len >= 8 && *buf_64 == pattern && *o_buf_64 == o_pattern) {
*buf_64 = repl;
if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -253,15 +273,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// reverse encoding
if (do_reverse)
if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl),
- idx, orig_buf, buf, len, 0, status)))
+ SWAP64(o_pattern), idx, orig_buf, buf,
+ len, 0, status)))
return 1;
}
if (SHAPE_BYTES(h->shape) == 4 || *status == 2) {
- if (its_len >= 4 &&
- *buf_32 == (u32)pattern) { // && *o_buf_32 == (u32)pattern) {
+ if (its_len >= 4 && *buf_32 == (u32)pattern &&
+ *o_buf_32 == (u32)o_pattern) {
*buf_32 = (u32)repl;
if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -272,15 +293,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// reverse encoding
if (do_reverse)
if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl),
- idx, orig_buf, buf, len, 0, status)))
+ SWAP32(o_pattern), idx, orig_buf, buf,
+ len, 0, status)))
return 1;
}
if (SHAPE_BYTES(h->shape) == 2 || *status == 2) {
- if (its_len >= 2 &&
- *buf_16 == (u16)pattern) { // && *o_buf_16 == (u16)pattern) {
+ if (its_len >= 2 && *buf_16 == (u16)pattern &&
+ *o_buf_16 == (u16)o_pattern) {
*buf_16 = (u16)repl;
if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -291,23 +313,23 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// reverse encoding
if (do_reverse)
if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl),
- idx, orig_buf, buf, len, 0, status)))
+ SWAP16(o_pattern), idx, orig_buf, buf,
+ len, 0, status)))
return 1;
}
- /*if (SHAPE_BYTES(h->shape) == 1 || *status == 2) {
+ if (SHAPE_BYTES(h->shape) == 1 || *status == 2) {
- if (its_len >= 2 && *buf_8 == (u8)pattern) {// && *o_buf_8 == (u8)pattern) {
+ if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) {
*buf_8 = (u8)repl;
- if (unlikely(its_fuzz(afl, buf, len, status)))
- return 1;
- *buf_16 = (u16)pattern;
+ if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
+ *buf_8 = (u8)pattern;
}
- }*/
+ }
return 0;
@@ -332,7 +354,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
}
- maybe_add_auto(afl, (u8 *)&v, shape);
+ maybe_add_auto((u8 *)afl, (u8 *)&v, shape);
u64 rev;
switch (shape) {
@@ -340,15 +362,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) {
case 1: break;
case 2:
rev = SWAP16((u16)v);
- maybe_add_auto(afl, (u8 *)&rev, shape);
+ maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
break;
case 4:
rev = SWAP32((u32)v);
- maybe_add_auto(afl, (u8 *)&rev, shape);
+ maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
break;
case 8:
rev = SWAP64(v);
- maybe_add_auto(afl, (u8 *)&rev, shape);
+ maybe_add_auto((u8 *)afl, (u8 *)&rev, shape);
break;
}
@@ -363,14 +385,44 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
u32 loggeds = h->hits;
if (h->hits > CMP_MAP_H) loggeds = CMP_MAP_H;
- u8 status;
+ u8 status = 0;
// opt not in the paper
- u32 fails = 0;
+ u32 fails;
+ u8 found_one = 0;
+
+ /* loop cmps are useless, detect and blacklist them */
+ u64 s_v0, s_v1;
+ u8 s_v0_fixed = 1, s_v1_fixed = 1;
+ u8 s_v0_inc = 1, s_v1_inc = 1;
+ u8 s_v0_dec = 1, s_v1_dec = 1;
for (i = 0; i < loggeds; ++i) {
+ fails = 0;
+
struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
+ // loop detection code
+ if (i == 0) {
+
+ s_v0 = o->v0;
+ s_v1 = o->v1;
+
+ } else {
+
+ if (s_v0 != o->v0) s_v0_fixed = 0;
+ if (s_v1 != o->v1) s_v1_fixed = 0;
+ if (s_v0 + 1 != o->v0) s_v0_inc = 0;
+ if (s_v1 + 1 != o->v1) s_v1_inc = 0;
+ if (s_v0 - 1 != o->v0) s_v0_dec = 0;
+ if (s_v1 - 1 != o->v1) s_v1_dec = 0;
+ s_v0 = o->v0;
+ s_v1 = o->v1;
+
+ }
+
+ struct cmp_operands *orig_o = &afl->orig_cmp_map->log[key][i];
+
// opt not in the paper
for (j = 0; j < i; ++j)
if (afl->shm.cmp_map->log[key][j].v0 == o->v0 &&
@@ -379,16 +431,16 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
for (idx = 0; idx < len && fails < 8; ++idx) {
- if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, idx, orig_buf, buf,
- len, 1, &status)))
+ if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx,
+ orig_buf, buf, len, 1, &status)))
return 1;
if (status == 2)
++fails;
else if (status == 1)
break;
- if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, idx, orig_buf, buf,
- len, 1, &status)))
+ if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx,
+ orig_buf, buf, len, 1, &status)))
return 1;
if (status == 2)
++fails;
@@ -397,11 +449,17 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
}
+ if (status == 1) found_one = 1;
+
// If failed, add to dictionary
if (fails == 8) {
- try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape));
- try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape));
+ if (afl->pass_stats[key].total == 0) {
+
+ try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape));
+ try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape));
+
+ }
}
@@ -410,13 +468,28 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
}
+ if (loggeds > 3 && ((s_v0_fixed && s_v1_inc) || (s_v1_fixed && s_v0_inc) ||
+ (s_v0_fixed && s_v1_dec) || (s_v1_fixed && s_v0_dec))) {
+
+ afl->pass_stats[key].total = afl->pass_stats[key].faileds = 0xff;
+
+ }
+
+ if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+ afl->pass_stats[key].faileds++;
+
+ }
+
+ if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++;
+
return 0;
}
static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h,
- u8 *pattern, u8 *repl, u32 idx, u8 *orig_buf,
- u8 *buf, u32 len, u8 *status) {
+ u8 *pattern, u8 *repl, u8 *o_pattern, u32 idx,
+ u8 *orig_buf, u8 *buf, u32 len, u8 *status) {
u32 i;
u32 its_len = MIN(32, len - idx);
@@ -428,7 +501,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h,
for (i = 0; i < its_len; ++i) {
- if (pattern[idx + i] != buf[idx + i] || *status == 1) break;
+ if (pattern[idx + i] != buf[idx + i] ||
+ o_pattern[idx + i] != orig_buf[idx + i] || *status == 1)
+ break;
buf[idx + i] = repl[idx + i];
if (unlikely(its_fuzz(afl, buf, len, status))) return 1;
@@ -448,15 +523,21 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
u32 loggeds = h->hits;
if (h->hits > CMP_MAP_RTN_H) loggeds = CMP_MAP_RTN_H;
- u8 status;
+ u8 status = 0;
// opt not in the paper
u32 fails = 0;
+ u8 found_one = 0;
for (i = 0; i < loggeds; ++i) {
+ fails = 0;
+
struct cmpfn_operands *o =
&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i];
+ struct cmpfn_operands *orig_o =
+ &((struct cmpfn_operands *)afl->orig_cmp_map->log[key])[i];
+
// opt not in the paper
for (j = 0; j < i; ++j)
if (!memcmp(&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[j], o,
@@ -465,16 +546,16 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
for (idx = 0; idx < len && fails < 8; ++idx) {
- if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, idx, orig_buf, buf,
- len, &status)))
+ if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx,
+ orig_buf, buf, len, &status)))
return 1;
if (status == 2)
++fails;
else if (status == 1)
break;
- if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, idx, orig_buf, buf,
- len, &status)))
+ if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx,
+ orig_buf, buf, len, &status)))
return 1;
if (status == 2)
++fails;
@@ -483,11 +564,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
}
+ if (status == 1) found_one = 1;
+
// If failed, add to dictionary
if (fails == 8) {
- maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape));
- maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape));
+ if (afl->pass_stats[key].total == 0) {
+
+ maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape));
+ maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape));
+
+ }
}
@@ -496,6 +583,14 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) {
}
+ if (!found_one && afl->pass_stats[key].faileds < 0xff) {
+
+ afl->pass_stats[key].faileds++;
+
+ }
+
+ if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++;
+
return 0;
}
@@ -507,6 +602,18 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
u32 exec_cksum) {
u8 r = 1;
+ if (afl->orig_cmp_map == NULL)
+ afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map));
+
+ if (afl->pass_stats == NULL)
+ afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W);
+
+ // do it manually, forkserver clear only afl->fsrv.trace_bits
+ memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers));
+
+ if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1;
+
+ memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map));
if (unlikely(colorization(afl, buf, len, exec_cksum))) return 1;
@@ -516,7 +623,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";
@@ -528,6 +635,13 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
for (k = 0; k < CMP_MAP_W; ++k) {
if (!afl->shm.cmp_map->headers[k].hits) continue;
+
+ if (afl->pass_stats[k].total &&
+ (rand_below(afl, afl->pass_stats[k].total) >=
+ afl->pass_stats[k].faileds ||
+ afl->pass_stats[k].total == 0xff))
+ afl->shm.cmp_map->headers[k].hits = 0; // blacklist this cmp
+
if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS)
afl->stage_max += MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_H);
else
@@ -555,11 +669,11 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len,
r = 0;
exit_its:
- memcpy(orig_buf, buf, len);
-
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);
return r;
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 47f6e9d9..30ba0e65 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -6,7 +6,8 @@
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -27,134 +28,18 @@
#include <sys/time.h>
#include <signal.h>
-/* 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, u32 timeout) {
-
- s32 res;
- u32 exec_ms;
-
- int status = 0;
- u32 tb4;
-
- afl->fsrv.child_timed_out = 0;
-
- /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we
- must prevent any earlier operations from venturing into that
- territory. */
-
- memset(afl->fsrv.trace_bits, 0, 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(afl->fsrv.fsrv_ctl_fd, &afl->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(afl->fsrv.fsrv_st_fd, &afl->fsrv.child_pid, 4)) != 4) {
-
- if (afl->stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
-
- }
-
- if (afl->fsrv.child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
-
- exec_ms = read_timed(afl->fsrv.fsrv_st_fd, &status, 4, timeout);
-
- 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(afl->fsrv.child_pid, SIGKILL);
- afl->fsrv.child_timed_out = 1;
- if (read(afl->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",
- afl->fsrv.mem_limit);
- RPFATAL(res, "Unable to communicate with fork server");
-
- }
-
- if (!WIFSTOPPED(status)) afl->fsrv.child_pid = 0;
-
- ++afl->total_execs;
-
- /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the
- compiler below this point. Past this location, afl->fsrv.trace_bits[]
- behave very normally and do not have to be treated as volatile. */
-
- MEM_BARRIER();
-
- tb4 = *(u32 *)afl->fsrv.trace_bits;
-
-#ifdef WORD_SIZE_64
- classify_counts((u64 *)afl->fsrv.trace_bits);
-#else
- classify_counts((u32 *)afl->fsrv.trace_bits);
-#endif /* ^WORD_SIZE_64 */
-
- afl->fsrv.prev_timed_out = afl->fsrv.child_timed_out;
-
- /* Report outcome to caller. */
-
- if (WIFSIGNALED(status) && !afl->stop_soon) {
-
- afl->kill_signal = WTERMSIG(status);
-
- if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL)
- return FAULT_TMOUT;
-
- return FAULT_CRASH;
-
- }
+#include "cmplog.h"
- /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and
- must use a special exit code. */
-
- if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) {
-
- afl->kill_signal = 0;
- return FAULT_CRASH;
-
- }
+/* Execute target application, monitoring for timeouts. Return status
+ information. The called program will update afl->fsrv->trace_bits. */
- if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG)
- return FAULT_ERROR;
+fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
+ u32 timeout) {
- return FAULT_NONE;
+ fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+ // TODO: Don't classify for faults?
+ classify_counts(fsrv);
+ return res;
}
@@ -164,13 +49,11 @@ u8 run_target(afl_state_t *afl, u32 timeout) {
void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
- s32 fd = afl->fsrv.out_fd;
-
#ifdef _AFL_DOCUMENT_MUTATIONS
s32 doc_fd;
char fn[PATH_MAX];
- snprintf(fn, PATH_MAX, ("%s/mutations/%09u:%s", afl->out_dir,
- afl->document_counter++, describe_op(afl, 0));
+ snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir,
+ afl->document_counter++, describe_op(afl, 0));
if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) {
@@ -182,25 +65,6 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
#endif
- if (afl->fsrv.out_file) {
-
- if (afl->no_unlink) {
-
- fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-
- } else {
-
- unlink(afl->fsrv.out_file); /* Ignore errors. */
- fd = open(afl->fsrv.out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
- }
-
- if (fd < 0) PFATAL("Unable to create '%s'", afl->fsrv.out_file);
-
- } else
-
- lseek(fd, 0, SEEK_SET);
-
if (unlikely(afl->mutator && afl->mutator->afl_custom_pre_save)) {
u8 *new_buf = NULL;
@@ -212,24 +76,15 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) {
FATAL("Custom_pre_save failed (ret: %lu)", (long unsigned)new_size);
/* everything as planned. use the new data. */
- ck_write(fd, new_buf, new_size, afl->fsrv.out_file);
+ afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size);
} else {
/* boring uncustom. */
- ck_write(fd, mem, len, afl->fsrv.out_file);
+ afl_fsrv_write_to_testcase(&afl->fsrv, mem, len);
}
- if (!afl->fsrv.out_file) {
-
- if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
- lseek(fd, 0, SEEK_SET);
-
- } else
-
- close(fd);
-
}
/* The same, but with an adjustable gap. Used for trimming. */
@@ -308,12 +163,22 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
/* Make sure the forkserver is up before we do anything, and let's not
count its spin-up time toward binary calibration. */
- if (!afl->fsrv.fsrv_pid) afl_fsrv_start(&afl->fsrv, afl->argv);
- if (afl->dumb_mode != 1 && !afl->no_forkserver && !afl->cmplog_fsrv_pid &&
- afl->shm.cmplog_mode)
- init_cmplog_forkserver(afl);
+ if (!afl->fsrv.fsrv_pid) {
+
+ if (afl->fsrv.cmplog_binary &&
+ afl->fsrv.init_child_func != cmplog_exec_child) {
+
+ FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly.");
+
+ }
+
+ afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child_output);
+
+ }
- if (q->exec_cksum) memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE);
+ if (q->exec_cksum)
+ memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
start_us = get_cur_time_us();
@@ -326,7 +191,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
write_to_testcase(afl, use_mem, q->len);
- fault = run_target(afl, use_tmout);
+ fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
@@ -334,14 +199,14 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration;
if (!afl->dumb_mode && !afl->stage_cur &&
- !count_bytes(afl->fsrv.trace_bits)) {
+ !count_bytes(afl, afl->fsrv.trace_bits)) {
- fault = FAULT_NOINST;
+ fault = FSRV_RUN_NOINST;
goto abort_calibration;
}
- cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
if (q->exec_cksum != cksum) {
@@ -352,7 +217,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
u32 i;
- for (i = 0; i < MAP_SIZE; ++i) {
+ for (i = 0; i < afl->fsrv.map_size; ++i) {
if (unlikely(!afl->var_bytes[i]) &&
unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i]))
@@ -366,7 +231,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
} else {
q->exec_cksum = cksum;
- memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE);
+ memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
}
@@ -383,7 +248,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
This is used for fuzzing air time calculations in calculate_score(). */
q->exec_us = (stop_us - start_us) / afl->stage_max;
- q->bitmap_size = count_bytes(afl->fsrv.trace_bits);
+ q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
q->handicap = handicap;
q->cal_failed = 0;
@@ -396,7 +261,8 @@ 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:
@@ -411,7 +277,7 @@ abort_calibration:
if (var_detected) {
- afl->var_byte_count = count_bytes(afl->var_bytes);
+ afl->var_byte_count = count_bytes(afl, afl->var_bytes);
if (!q->var_behavior) {
@@ -543,7 +409,7 @@ void sync_fuzzers(afl_state_t *afl) {
write_to_testcase(afl, mem, st.st_size);
- fault = run_target(afl, afl->fsrv.exec_tmout);
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
if (afl->stop_soon) goto close_sync;
@@ -630,15 +496,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
write_with_gap(afl, in_buf, q->len, remove_pos, trim_avail);
- fault = run_target(afl, afl->fsrv.exec_tmout);
+ fault = fuzz_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?
*/
- cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST);
+ cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
/* If the deletion had no impact on the trace, make it permanent. This
isn't perfect for variable-path inputs, but we're just making a
@@ -661,7 +527,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
if (!needs_write) {
needs_write = 1;
- memcpy(afl->clean_trace, afl->fsrv.trace_bits, MAP_SIZE);
+ memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size);
}
@@ -703,7 +569,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
ck_write(fd, in_buf, q->len, q->fname);
close(fd);
- memcpy(afl->fsrv.trace_bits, afl->clean_trace, MAP_SIZE);
+ memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size);
update_bitmap_score(afl, q);
}
@@ -737,11 +603,11 @@ u8 common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
write_to_testcase(afl, out_buf, len);
- fault = run_target(afl, afl->fsrv.exec_tmout);
+ fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
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-state.c b/src/afl-fuzz-state.c
index 80176a10..de7a4481 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -75,12 +75,14 @@ list_t afl_states = {.element_prealloc_count = 0};
/* Initializes an afl_state_t. */
-void afl_state_init(afl_state_t *afl) {
+void afl_state_init(afl_state_t *afl, uint32_t map_size) {
/* thanks to this memset, growing vars like out_buf
and out_size are NULL/0 by default. */
memset(afl, 0, sizeof(afl_state_t));
+ if (!map_size) afl->shm.map_size = MAP_SIZE;
+
afl->w_init = 0.9;
afl->w_end = 0.3;
afl->g_max = 5000;
@@ -97,7 +99,20 @@ void afl_state_init(afl_state_t *afl) {
afl->cpu_aff = -1; /* Selected CPU core */
#endif /* HAVE_AFFINITY */
+ afl->virgin_bits = ck_alloc(map_size);
+ afl->virgin_tmout = ck_alloc(map_size);
+ afl->virgin_crash = ck_alloc(map_size);
+ afl->var_bytes = ck_alloc(map_size);
+ afl->top_rated = ck_alloc(map_size * sizeof(void *));
+ afl->clean_trace = ck_alloc(map_size);
+ afl->clean_trace_custom = ck_alloc(map_size);
+ afl->first_trace = ck_alloc(map_size);
+ afl->map_tmp_buf = ck_alloc(map_size);
+
afl->fsrv.use_stdin = 1;
+ afl->fsrv.map_size = map_size;
+ afl->fsrv.function_opt = (u8 *)afl;
+ afl->fsrv.function_ptr = &maybe_add_auto;
afl->cal_cycles = CAL_CYCLES;
afl->cal_cycles_long = CAL_CYCLES_LONG;
@@ -280,6 +295,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_autoresume =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_CAL_FAST",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_cal_fast =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_TMPDIR",
afl_environment_variable_len)) {
@@ -348,13 +370,27 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
void afl_state_deinit(afl_state_t *afl) {
if (afl->post_deinit) afl->post_deinit(afl->post_data);
-
- free(afl->out_buf);
- free(afl->out_scratch_buf);
- free(afl->eff_buf);
- free(afl->in_buf);
- free(afl->in_scratch_buf);
- free(afl->ex_buf);
+ if (afl->in_place_resume) ck_free(afl->in_dir);
+ if (afl->sync_id) ck_free(afl->out_dir);
+ if (afl->pass_stats) ck_free(afl->pass_stats);
+ if (afl->orig_cmp_map) ck_free(afl->orig_cmp_map);
+
+ if (afl->out_buf) free(afl->out_buf);
+ if (afl->out_scratch_buf) free(afl->out_scratch_buf);
+ if (afl->eff_buf) free(afl->eff_buf);
+ if (afl->in_buf) free(afl->in_buf);
+ if (afl->in_scratch_buf) free(afl->in_scratch_buf);
+ if (afl->ex_buf) free(afl->ex_buf);
+
+ ck_free(afl->virgin_bits);
+ ck_free(afl->virgin_tmout);
+ ck_free(afl->virgin_crash);
+ ck_free(afl->var_bytes);
+ ck_free(afl->top_rated);
+ ck_free(afl->clean_trace);
+ ck_free(afl->clean_trace_custom);
+ ck_free(afl->first_trace);
+ ck_free(afl->map_tmp_buf);
list_remove(&afl_states, afl);
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 850555b5..c507b7f7 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -37,7 +37,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
u8 fn[PATH_MAX];
s32 fd;
FILE * f;
- uint32_t t_bytes = count_non_255_bytes(afl->virgin_bits);
+ uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
@@ -56,7 +56,6 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
bitmap_cvg = afl->last_bitmap_cvg;
stability = afl->last_stability;
- eps = afl->last_eps;
} else {
@@ -109,14 +108,15 @@ 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),
@@ -124,12 +124,12 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
(unsigned long int)(rus.ru_maxrss >> 10),
#endif
t_bytes, afl->var_byte_count, afl->use_banner,
- afl->unicorn_mode ? "unicorn" : "", afl->qemu_mode ? "qemu " : "",
+ afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "",
afl->dumb_mode ? " dumb " : "", afl->no_forkserver ? "no_fsrv " : "",
afl->crash_mode ? "crash " : "",
afl->persistent_mode ? "persistent " : "",
afl->deferred_mode ? "deferred " : "",
- (afl->unicorn_mode || afl->qemu_mode || afl->dumb_mode ||
+ (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->dumb_mode ||
afl->no_forkserver || afl->crash_mode || afl->persistent_mode ||
afl->deferred_mode)
? ""
@@ -145,14 +145,15 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability,
void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) {
- if (afl->plot_prev_qp == afl->queued_paths &&
- afl->plot_prev_pf == afl->pending_favored &&
- afl->plot_prev_pnf == afl->pending_not_fuzzed &&
- afl->plot_prev_ce == afl->current_entry &&
- afl->plot_prev_qc == afl->queue_cycle &&
- afl->plot_prev_uc == afl->unique_crashes &&
- afl->plot_prev_uh == afl->unique_hangs &&
- afl->plot_prev_md == afl->max_depth)
+ if (unlikely(afl->plot_prev_qp == afl->queued_paths &&
+ afl->plot_prev_pf == afl->pending_favored &&
+ afl->plot_prev_pnf == afl->pending_not_fuzzed &&
+ afl->plot_prev_ce == afl->current_entry &&
+ afl->plot_prev_qc == afl->queue_cycle &&
+ afl->plot_prev_uc == afl->unique_crashes &&
+ afl->plot_prev_uh == afl->unique_hangs &&
+ afl->plot_prev_md == afl->max_depth) ||
+ unlikely(!afl->queue_cycle))
return;
afl->plot_prev_qp = afl->queued_paths;
@@ -215,6 +216,28 @@ void show_stats(afl_state_t *afl) {
cur_ms = get_cur_time();
+ if (afl->most_time_key) {
+
+ if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+
+ afl->most_time_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
+ if (afl->most_execs_key == 1) {
+
+ if (afl->most_execs <= afl->fsrv.total_execs) {
+
+ afl->most_execs_key = 2;
+ afl->stop_soon = 2;
+
+ }
+
+ }
+
/* If not enough time has passed since last UI update, bail out. */
if (cur_ms - afl->stats_last_ms < 1000 / UI_TARGET_HZ &&
@@ -230,11 +253,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
@@ -249,7 +272,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). */
@@ -258,8 +281,8 @@ void show_stats(afl_state_t *afl) {
/* Do some bitmap stats. */
- t_bytes = count_non_255_bytes(afl->virgin_bits);
- t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE;
+ t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
+ t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size;
if (likely(t_bytes) && unlikely(afl->var_byte_count))
stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes);
@@ -305,7 +328,7 @@ void show_stats(afl_state_t *afl) {
/* Compute some mildly useful bitmap stats. */
- t_bits = (MAP_SIZE << 3) - count_bits(afl->virgin_bits);
+ t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits);
/* Now, for the visuals... */
@@ -465,7 +488,8 @@ void show_stats(afl_state_t *afl) {
SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp);
sprintf(tmp, "%0.02f%% / %0.02f%%",
- ((double)afl->queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio);
+ ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size,
+ t_byte_ratio);
SAYF(" map density : %s%-21s" bSTG bV "\n",
t_byte_ratio > 70 ? cLRD
@@ -521,14 +545,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);
}
@@ -736,6 +760,8 @@ void show_stats(afl_state_t *afl) {
if (afl->cpu_core_count) {
+ char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " ";
+
double cur_runnable = get_runnable_processes();
u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count;
@@ -750,23 +776,25 @@ void show_stats(afl_state_t *afl) {
if (!afl->no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD;
+ if (afl->fsrv.snapshot) spacing = snap;
+
#ifdef HAVE_AFFINITY
if (afl->cpu_aff >= 0) {
- SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(afl->cpu_aff, 999),
- cpu_color, MIN(cur_utilization, 999));
+ SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing,
+ MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, 999));
} else {
- SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
MIN(cur_utilization, 999));
}
#else
- SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color,
+ SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color,
MIN(cur_utilization, 999));
#endif /* ^HAVE_AFFINITY */
@@ -819,7 +847,7 @@ void show_init_stats(afl_state_t *afl) {
SAYF("\n");
- if (avg_us > ((afl->qemu_mode || afl->unicorn_mode) ? 50000 : 10000))
+ if (avg_us > ((afl->fsrv.qemu_mode || afl->unicorn_mode) ? 50000 : 10000))
WARNF(cLRD "The target binary is pretty slow! See %s/perf_tips.md.",
doc_path);
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 5010c3ea..efb65ba6 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -24,6 +24,8 @@
*/
#include "afl-fuzz.h"
+#include "cmplog.h"
+#include <limits.h>
static u8 *get_libradamsa_path(u8 *own_loc) {
@@ -108,12 +110,12 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
"Mutator settings:\n"
" -R[R] - add Radamsa as mutator, add another -R to exclusivly "
"run it\n"
- " -L minutes - use MOpt(imize) mode and set the limit time for "
+ " -L minutes - use MOpt(imize) mode and set the time limit for "
"entering the\n"
- " pacemaker mode (minutes of no new paths, 0 = "
- "immediately).\n"
- " a recommended value is 10-60. see "
- "docs/README.MOpt.md\n"
+ " pacemaker mode (minutes of no new paths). 0 = "
+ "immediately,\n"
+ " -1 = immediately and together with normal mutation).\n"
+ " See docs/README.MOpt.md\n"
" -c program - enable CmpLog by specifying a binary compiled for "
"it.\n"
" if using QEMU, just use -c 0.\n\n"
@@ -128,12 +130,11 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
"Testing settings:\n"
" -s seed - use a fixed seed for the RNG\n"
- " -V seconds - fuzz for a maximum total time of seconds then "
+ " -V seconds - fuzz for a specific time then terminate\n"
+ " -E execs - fuzz for a approx. no of total executions then "
"terminate\n"
- " -E execs - fuzz for a maximum number of total executions then "
- "terminate\n"
- " Note: -V/-E are not precise, they are checked after a queue entry "
- "is done\n which can be many minutes/execs later\n\n"
+ " Note: not precise and can have several more "
+ "executions.\n\n"
"Other stuff:\n"
" -T text - text banner to show on the screen\n"
@@ -143,51 +144,53 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
" -B bitmap.txt - mutate a specific test case, use the out/fuzz_bitmap "
"file\n"
" -C - crash exploration mode (the peruvian rabbit thing)\n"
- " -e ext - File extension for the temporarily generated test "
+ " -e ext - file extension for the temporarily generated test "
"case\n\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT);
if (more_help > 1)
SAYF(
"Environment variables used:\n"
- "AFL_PATH: path to AFL support binaries\n"
- "AFL_QUIET: suppress forkserver status messages\n"
- "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
+ "ASAN_OPTIONS: custom settings for ASAN\n"
+ " (must contain abort_on_error=1 and symbolize=0)\n"
+ "MSAN_OPTIONS: custom settings for MSAN\n"
+ " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
"AFL_BENCH_JUST_ONE: run the target just once\n"
- "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
+ "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
"AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n"
"AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
- "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
"AFL_DEBUG: extra debugging output for Python mode trimming\n"
+ "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n"
"AFL_DISABLE_TRIM: disable the trimming of test cases\n"
- "AFL_NO_UI: switch status screen off\n"
- "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
- "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
- "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
- "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
- "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
- "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
- "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
+ "AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
+ "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
"AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
+ "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n"
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
- "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
- "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
+ "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
"AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n"
+ "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n"
+ "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n"
+ "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
+ "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
+ "AFL_NO_UI: switch status screen off\n"
+ "AFL_PATH: path to AFL support binaries\n"
"AFL_POST_LIBRARY: postprocess generated test cases before use as target input\n"
- "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
- "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
- "ASAN_OPTIONS: custom settings for ASAN\n"
- " (must contain abort_on_error=1 and symbolize=0)\n"
- "MSAN_OPTIONS: custom settings for MSAN\n"
- " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
+ "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n"
+ "AFL_QUIET: suppress forkserver status messages\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
"AFL_SKIP_BIN_CHECK: skip the check, if the target is an excutable\n"
+ "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n"
+ "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n"
+ "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
//"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n"
//"AFL_DEFER_FORKSRV: not supported anymore -> no effect, just a warning\n"
- "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
- "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
- "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
"\n"
);
else
@@ -213,6 +216,8 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) {
static int stricmp(char const *a, char const *b) {
+ if (!a || !b) FATAL("Null reference");
+
for (;; ++a, ++b) {
int d;
@@ -229,7 +234,7 @@ int main(int argc, char **argv_orig, char **envp) {
s32 opt;
u64 prev_queued = 0;
- u32 sync_interval_cnt = 0, seek_to, show_help = 0;
+ u32 sync_interval_cnt = 0, seek_to, show_help = 0, map_size = MAP_SIZE;
u8 * extras_dir = 0;
u8 mem_limit_given = 0, exit_1 = 0;
char **use_argv;
@@ -242,10 +247,14 @@ int main(int argc, char **argv_orig, char **envp) {
afl_state_t *afl = calloc(1, sizeof(afl_state_t));
if (!afl) { FATAL("Could not create afl state"); }
- afl_state_init(afl);
+ if (get_afl_env("AFL_DEBUG")) afl->debug = 1;
+
+ map_size = get_map_size();
+ afl_state_init(afl, map_size);
afl_fsrv_init(&afl->fsrv);
read_afl_environment(afl, envp);
+ if (afl->shm.map_size) afl->fsrv.map_size = afl->shm.map_size;
exit_1 = !!afl->afl_env.afl_bench_just_one;
SAYF(cCYA "afl-fuzz" VERSION cRST
@@ -417,6 +426,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1;
+ if (!optarg) FATAL("Wrong usage of -m");
+
if (!strcmp(optarg, "none")) {
afl->fsrv.mem_limit = 0;
@@ -471,13 +482,13 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->in_bitmap) FATAL("Multiple -B options not supported");
afl->in_bitmap = optarg;
- read_bitmap(afl, afl->in_bitmap);
+ read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size);
break;
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 */
@@ -498,8 +509,8 @@ int main(int argc, char **argv_orig, char **envp) {
case 'Q': /* QEMU mode */
- if (afl->qemu_mode) FATAL("Multiple -Q options not supported");
- afl->qemu_mode = 1;
+ if (afl->fsrv.qemu_mode) FATAL("Multiple -Q options not supported");
+ afl->fsrv.qemu_mode = 1;
if (!mem_limit_given) afl->fsrv.mem_limit = MEM_LIMIT_QEMU;
@@ -524,7 +535,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'W': /* Wine+QEMU mode */
if (afl->use_wine) FATAL("Multiple -W options not supported");
- afl->qemu_mode = 1;
+ afl->fsrv.qemu_mode = 1;
afl->use_wine = 1;
if (!mem_limit_given) afl->fsrv.mem_limit = 0;
@@ -550,20 +561,33 @@ int main(int argc, char **argv_orig, char **envp) {
case 'L': { /* MOpt mode */
if (afl->limit_time_sig) FATAL("Multiple -L options not supported");
- afl->limit_time_sig = 1;
afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT;
- if (sscanf(optarg, "%llu", &afl->limit_time_puppet) < 1 ||
- optarg[0] == '-')
+ if (sscanf(optarg, "%d", &afl->limit_time_puppet) < 1)
FATAL("Bad syntax used for -L");
+ if (afl->limit_time_puppet == -1) {
+
+ afl->limit_time_sig = -1;
+ afl->limit_time_puppet = 0;
+
+ } else if (afl->limit_time_puppet < 0) {
+
+ FATAL("-L value must be between 0 and 2000000 or -1");
+
+ } else {
+
+ afl->limit_time_sig = 1;
+
+ }
+
u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;
if (limit_time_puppet2 < afl->limit_time_puppet)
FATAL("limit_time overflow");
afl->limit_time_puppet = limit_time_puppet2;
- SAYF("limit_time_puppet %llu\n", afl->limit_time_puppet);
+ SAYF("limit_time_puppet %d\n", afl->limit_time_puppet);
afl->swarm_now = 0;
if (afl->limit_time_puppet == 0) afl->key_puppet = 1;
@@ -687,7 +711,7 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL");
if (afl->sync_id && afl->force_deterministic &&
- getenv("AFL_CUSTOM_MUTATOR_ONLY"))
+ afl->afl_env.afl_custom_mutator_only)
WARNF(
"Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will "
"result in no deterministic mutations being done!");
@@ -698,11 +722,14 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->use_radamsa) {
- if (afl->limit_time_sig)
+ if (afl->limit_time_sig > 0)
FATAL(
- "MOpt and Radamsa are mutually exclusive. We accept pull requests "
- "that integrates MOpt with the optional mutators "
- "(custom/radamsa/redquenn/...).");
+ "MOpt and Radamsa are mutually exclusive unless you specify -L -1. "
+ "We accept pull requests that integrates MOpt with the optional "
+ "mutators (custom/radamsa/redqueen/...).");
+
+ if (afl->limit_time_sig && afl->use_radamsa > 1)
+ FATAL("Radamsa in radamsa-only mode can not run together with -L");
OKF("Using Radamsa add-on");
@@ -748,7 +775,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->dumb_mode) {
if (afl->crash_mode) FATAL("-C and -n are mutually exclusive");
- if (afl->qemu_mode) FATAL("-Q and -n are mutually exclusive");
+ if (afl->fsrv.qemu_mode) FATAL("-Q and -n are mutually exclusive");
if (afl->unicorn_mode) FATAL("-U and -n are mutually exclusive");
}
@@ -816,7 +843,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->afl_env.afl_preload) {
- if (afl->qemu_mode) {
+ if (afl->fsrv.qemu_mode) {
u8 *qemu_preload = getenv("QEMU_SET_ENV");
u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -862,7 +889,7 @@ int main(int argc, char **argv_orig, char **envp) {
check_if_tty(afl);
if (afl->afl_env.afl_force_ui) afl->not_on_tty = 0;
- if (get_afl_env("AFL_CAL_FAST")) {
+ if (afl->afl_env.afl_cal_fast) {
/* Use less calibration cycles, for slow applications */
afl->cal_cycles = 3;
@@ -870,8 +897,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (get_afl_env("AFL_DEBUG")) afl->debug = 1;
-
if (afl->afl_env.afl_custom_mutator_only) {
/* This ensures we don't proceed to havoc/splice */
@@ -891,13 +916,14 @@ int main(int argc, char **argv_orig, char **envp) {
check_crash_handling();
check_cpu_governor(afl);
- afl->fsrv.trace_bits = afl_shm_init(&afl->shm, MAP_SIZE, afl->dumb_mode);
+ afl->fsrv.trace_bits =
+ afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->dumb_mode);
setup_post(afl);
- if (!afl->in_bitmap) memset(afl->virgin_bits, 255, MAP_SIZE);
- memset(afl->virgin_tmout, 255, MAP_SIZE);
- memset(afl->virgin_crash, 255, MAP_SIZE);
+ if (!afl->in_bitmap) memset(afl->virgin_bits, 255, afl->fsrv.map_size);
+ memset(afl->virgin_tmout, 255, afl->fsrv.map_size);
+ memset(afl->virgin_crash, 255, afl->fsrv.map_size);
init_count_class16();
@@ -919,21 +945,21 @@ int main(int argc, char **argv_orig, char **envp) {
if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
!afl->in_place_resume) {
- char tmpfile[afl->file_extension ? strlen(afl->tmp_dir) + 1 + 10 + 1 +
- strlen(afl->file_extension) + 1
- : strlen(afl->tmp_dir) + 1 + 10 + 1];
+ char tmpfile[PATH_MAX];
+
if (afl->file_extension) {
- sprintf(tmpfile, "%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+ snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir,
+ afl->file_extension);
} else {
- sprintf(tmpfile, "%s/.cur_input", afl->tmp_dir);
+ snprintf(tmpfile, PATH_MAX, "%s/.cur_input", afl->tmp_dir);
}
- if (access(tmpfile, F_OK) !=
- -1) // there is still a race condition here, but well ...
+ /* there is still a race condition here, but well ... */
+ if (access(tmpfile, F_OK) != -1)
FATAL(
"AFL_TMPDIR already has an existing temporary input file: %s - if "
"this is not from another instance, then just remove the file.",
@@ -983,15 +1009,9 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->cmplog_binary) {
- if (afl->limit_time_sig)
- FATAL(
- "MOpt and CmpLog are mutually exclusive. We accept pull requests "
- "that integrates MOpt with the optional mutators "
- "(custom/radamsa/redquenn/...).");
-
if (afl->unicorn_mode)
FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry");
- if (!afl->qemu_mode) check_binary(afl, afl->cmplog_binary);
+ if (!afl->fsrv.qemu_mode) check_binary(afl, afl->cmplog_binary);
}
@@ -999,7 +1019,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->start_time = get_cur_time();
- if (afl->qemu_mode) {
+ if (afl->fsrv.qemu_mode) {
if (afl->use_wine)
use_argv = get_wine_argv(argv[0], &afl->fsrv.target_path, argc - optind,
@@ -1015,6 +1035,21 @@ int main(int argc, char **argv_orig, char **envp) {
}
afl->argv = use_argv;
+
+ if (afl->cmplog_binary) {
+
+ ACTF("Spawning cmplog forkserver");
+ afl_fsrv_init_dup(&afl->cmplog_fsrv, &afl->fsrv);
+ // TODO: this is semi-nice
+ afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
+ afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
+ afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
+ afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
+ afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
+ afl->afl_env.afl_debug_child_output);
+
+ }
+
perform_dry_run(afl);
cull_queue(afl);
@@ -1109,55 +1144,6 @@ int main(int argc, char **argv_orig, char **envp) {
afl->queue_cur = afl->queue_cur->next;
++afl->current_entry;
- if (afl->most_time_key == 1) {
-
- u64 cur_ms_lv = get_cur_time();
- if (afl->most_time * 1000 < cur_ms_lv - afl->start_time) {
-
- afl->most_time_key = 2;
- afl->stop_soon = 2;
- break;
-
- }
-
- }
-
- if (afl->most_execs_key == 1) {
-
- if (afl->most_execs <= afl->total_execs) {
-
- afl->most_execs_key = 2;
- afl->stop_soon = 2;
- break;
-
- }
-
- }
-
- }
-
- // if (afl->queue_cur) show_stats(afl);
-
- /*
- * ATTENTION - the following 10 lines were copied from a PR to Google's afl
- * repository - and slightly fixed.
- * These lines have nothing to do with the purpose of original PR though.
- * Looks like when an exit condition was completed (AFL_BENCH_JUST_ONE,
- * AFL_EXIT_WHEN_DONE or AFL_BENCH_UNTIL_CRASH) the child and forkserver
- * where not killed?
- */
- /* if we stopped programmatically, we kill the forkserver and the current
- runner. if we stopped manually, this is done by the signal handler */
- if (afl->stop_soon == 2) {
-
- if (afl->fsrv.child_pid > 0) kill(afl->fsrv.child_pid, SIGKILL);
- if (afl->fsrv.fsrv_pid > 0) kill(afl->fsrv.fsrv_pid, SIGKILL);
- if (afl->cmplog_child_pid > 0) kill(afl->cmplog_child_pid, SIGKILL);
- if (afl->cmplog_fsrv_pid > 0) kill(afl->cmplog_fsrv_pid, SIGKILL);
- /* Now that we've killed the forkserver, we wait for it to be able to get
- * rusage stats. */
- if (waitpid(afl->fsrv.fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); }
-
}
write_bitmap(afl);
@@ -1200,6 +1186,7 @@ stop_fuzzing:
ck_free(afl->fsrv.target_path);
ck_free(afl->fsrv.out_file);
ck_free(afl->sync_id);
+ afl_state_deinit(afl);
free(afl); /* not tracked */
argv_cpy_free(argv);
diff --git a/src/afl-gcc.c b/src/afl-gcc.c
index b0153b49..1ae10975 100644
--- a/src/afl-gcc.c
+++ b/src/afl-gcc.c
@@ -142,12 +142,12 @@ static void edit_params(u32 argc, char **argv) {
if (!strcmp(name, "afl-clang++")) {
u8 *alt_cxx = getenv("AFL_CXX");
- cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++";
+ cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++";
} else {
u8 *alt_cc = getenv("AFL_CC");
- cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang";
+ cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang";
}
@@ -187,17 +187,17 @@ static void edit_params(u32 argc, char **argv) {
if (!strcmp(name, "afl-g++")) {
u8 *alt_cxx = getenv("AFL_CXX");
- cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++";
+ cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++";
} else if (!strcmp(name, "afl-gcj")) {
u8 *alt_cc = getenv("AFL_GCJ");
- cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj";
+ cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj";
} else {
u8 *alt_cc = getenv("AFL_CC");
- cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc";
+ cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc";
}
@@ -411,6 +411,15 @@ int main(int argc, char **argv) {
}
+ u8 *ptr;
+ if (!be_quiet &&
+ ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) {
+
+ u32 map_size = atoi(ptr);
+ if (map_size != MAP_SIZE) FATAL("AFL_MAP_SIZE is not supported by afl-gcc");
+
+ }
+
find_as(argv[0]);
edit_params(argc, argv);
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index 7bdf8d03..a130411e 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>
@@ -61,18 +60,19 @@
#include <sys/shm.h>
#endif
-list_t shm_list = {.element_prealloc_count = 0};
+static list_t shm_list = {.element_prealloc_count = 0};
/* Get rid of shared memory. */
void afl_shm_deinit(sharedmem_t *shm) {
+ // TODO: clang reports a potential UAF in this function/makro(?)
list_remove(&shm_list, shm);
#ifdef USEMMAP
if (shm->map != NULL) {
- munmap(shm->map, shm->size_alloc);
+ munmap(shm->map, shm->map_size);
shm->map = NULL;
}
@@ -93,21 +93,13 @@ void afl_shm_deinit(sharedmem_t *shm) {
}
-/* At exit, remove all leftover maps */
-
-void afl_shm_atexit() {
-
- LIST_FOREACH(&shm_list, sharedmem_t, { afl_shm_deinit(el); });
-
-}
-
/* Configure shared memory.
Returns a pointer to shm->map for ease of use.
*/
u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
- shm->size_alloc = shm->size_used = map_size;
+ shm->map_size = map_size;
shm->map = NULL;
@@ -207,7 +199,6 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) {
#endif
list_append(&shm_list, shm);
- atexit(afl_shm_atexit);
return shm->map;
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index e4463dc4..59b4963d 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -8,7 +8,8 @@
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -51,6 +52,7 @@
#include <signal.h>
#include <dirent.h>
#include <fcntl.h>
+#include <limits.h>
#include <sys/wait.h>
#include <sys/time.h>
@@ -59,19 +61,21 @@
#include <sys/types.h>
#include <sys/resource.h>
-char *stdin_file; /* stdin file */
+static char *stdin_file; /* stdin file */
-u8 *in_dir, /* input folder */
- *at_file = NULL; /* Substitution string for @@ */
+static u8 *in_dir = NULL, /* input folder */
+ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
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 */
-u8 quiet_mode, /* Hide non-essential messages? */
+static u32 map_size = MAP_SIZE;
+
+static u8 quiet_mode, /* Hide non-essential messages? */
edges_only, /* Ignore hit counts? */
raw_instr_output, /* Do not apply AFL filters */
cmin_mode, /* Generate output in afl-cmin mode? */
@@ -81,8 +85,6 @@ u8 quiet_mode, /* Hide non-essential messages? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_crashed; /* Child crashed? */
-static u8 qemu_mode;
-
/* Classify tuple counts. Instead of mapping to individual bits, as in
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
@@ -108,9 +110,12 @@ static const u8 count_class_binary[256] = {
};
-static void classify_counts(u8 *mem, const u8 *map) {
+static void classify_counts(afl_forkserver_t *fsrv) {
- u32 i = MAP_SIZE;
+ u8 * mem = fsrv->trace_bits;
+ const u8 *map = binary_mode ? count_class_binary : count_class_human;
+
+ u32 i = map_size;
if (edges_only) {
@@ -156,7 +161,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
fd = open(outfile, O_WRONLY);
- if (fd < 0) PFATAL("Unable to open '%s'", fsrv->out_file);
+ if (fd < 0) PFATAL("Unable to open '%s'", out_file);
} else if (!strcmp(outfile, "-")) {
@@ -173,10 +178,10 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (binary_mode) {
- for (i = 0; i < MAP_SIZE; i++)
+ for (i = 0; i < map_size; i++)
if (fsrv->trace_bits[i]) ret++;
- ck_write(fd, fsrv->trace_bits, MAP_SIZE, outfile);
+ ck_write(fd, fsrv->trace_bits, map_size, outfile);
close(fd);
} else {
@@ -185,7 +190,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (!f) PFATAL("fdopen() failed");
- for (i = 0; i < MAP_SIZE; i++) {
+ for (i = 0; i < map_size; i++) {
if (!fsrv->trace_bits[i]) continue;
ret++;
@@ -195,7 +200,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);
@@ -214,96 +219,21 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
}
-/* Write results. */
-
-static u32 write_results(afl_forkserver_t *fsrv) {
-
- return write_results_to_file(fsrv, fsrv->out_file);
-
-}
-
-/* Write modified data to file for testing. If use_stdin is clear, the old file
- is unlinked and a new one is created. Otherwise, out_fd is rewound and
- truncated. */
-
-static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
-
- lseek(fsrv->out_fd, 0, SEEK_SET);
- ck_write(fsrv->out_fd, mem, len, fsrv->out_file);
- if (ftruncate(fsrv->out_fd, len)) PFATAL("ftruncate() failed");
- lseek(fsrv->out_fd, 0, SEEK_SET);
-
-}
-
-/* Execute target application. Returns 0 if the changes are a dud, or
- 1 if they should be kept. */
-
-static u8 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) {
+/* Execute target application. */
- if (stop_soon) return 0;
- RPFATAL(res, "Unable to request new process from fork server (OOM?)");
+static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, char **argv,
+ u8 *mem, u32 len) {
- }
+ afl_fsrv_write_to_testcase(fsrv, mem, len);
- if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+ if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+ FSRV_RUN_ERROR) {
- /* 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;
+ FATAL("Error running target");
}
- 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]);
-
- classify_counts(fsrv->trace_bits,
- binary_mode ? count_class_binary : count_class_human);
- total_execs++;
+ classify_counts(fsrv);
if (stop_soon) {
@@ -312,27 +242,11 @@ 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. */
-u32 read_file(u8 *in_file) {
+static u32 read_file(u8 *in_file) {
struct stat st;
s32 fd = open(in_file, O_RDONLY);
@@ -357,7 +271,7 @@ u32 read_file(u8 *in_file) {
/* Execute target application. */
-static void run_target(afl_forkserver_t *fsrv, char **argv) {
+static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
static struct itimerval it;
int status = 0;
@@ -427,7 +341,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;
@@ -449,17 +363,16 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) {
if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG)
FATAL("Unable to execute '%s'", argv[0]);
- classify_counts(fsrv->trace_bits,
- binary_mode ? count_class_binary : count_class_human);
+ classify_counts(fsrv);
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);
@@ -482,7 +395,7 @@ static void handle_stop_sig(int sig) {
/* Do basic preparations - persistent fds, filenames, etc. */
-static void set_up_environment(void) {
+static void set_up_environment(afl_forkserver_t *fsrv) {
setenv("ASAN_OPTIONS",
"abort_on_error=1:"
@@ -499,7 +412,7 @@ static void set_up_environment(void) {
if (get_afl_env("AFL_PRELOAD")) {
- if (qemu_mode) {
+ if (fsrv->qemu_mode) {
u8 *qemu_preload = getenv("QEMU_SET_ENV");
u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -576,11 +489,9 @@ static void usage(u8 *argv0) {
"\n%s [ options ] -- /path/to/target_app [ ... ]\n\n"
"Required parameters:\n"
-
" -o file - file to write the trace data to\n\n"
"Execution control settings:\n"
-
" -t msec - timeout for each run (none)\n"
" -m megs - memory limit for child process (%d MB)\n"
" -Q - use binary-only instrumentation (QEMU mode)\n"
@@ -588,9 +499,7 @@ static void usage(u8 *argv0) {
" -W - use qemu-based instrumentation with Wine (Wine mode)\n"
" (Not necessary, here for consistency with other afl-* "
"tools)\n\n"
-
"Other settings:\n"
-
" -i dir - process all files in this directory, -o must be a "
"directory\n"
" and each bitmap will be written there individually.\n"
@@ -603,75 +512,22 @@ static void usage(u8 *argv0) {
"For additional help, consult %s/README.md.\n\n"
"Environment variables used:\n"
- "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
- "AFL_DEBUG: enable extra developer output\n"
- "AFL_QUIET: do not print extra informational output"
+ "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
"inputs\n"
"AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
- "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n",
+ "AFL_DEBUG: enable extra developer output\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
+ "size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_QUIET: do not print extra informational output",
argv0, MEM_LIMIT, doc_path);
exit(1);
}
-/* Find binary. */
-
-static void find_binary(afl_forkserver_t *fsrv, u8 *fname) {
-
- u8 * env_path = 0;
- struct stat st;
-
- if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
- fsrv->target_path = ck_strdup(fname);
-
- if (stat(fsrv->target_path, &st) || !S_ISREG(st.st_mode) ||
- !(st.st_mode & 0111) || st.st_size < 4)
- FATAL("Program '%s' not found or not executable", fname);
-
- } else {
-
- while (env_path) {
-
- u8 *cur_elem, *delim = strchr(env_path, ':');
-
- if (delim) {
-
- cur_elem = ck_alloc(delim - env_path + 1);
- memcpy(cur_elem, env_path, delim - env_path);
- delim++;
-
- } else
-
- cur_elem = ck_strdup(env_path);
-
- env_path = delim;
-
- if (cur_elem[0])
- fsrv->target_path = alloc_printf("%s/%s", cur_elem, fname);
- else
- fsrv->target_path = ck_strdup(fname);
-
- ck_free(cur_elem);
-
- if (!stat(fsrv->target_path, &st) && S_ISREG(st.st_mode) &&
- (st.st_mode & 0111) && st.st_size >= 4)
- break;
-
- ck_free(fsrv->target_path);
- fsrv->target_path = 0;
-
- }
-
- if (!fsrv->target_path)
- FATAL("Program '%s' not found or not executable", fname);
-
- }
-
-}
-
/* Main entry point */
int main(int argc, char **argv_orig, char **envp) {
@@ -688,6 +544,8 @@ int main(int argc, char **argv_orig, char **envp) {
afl_forkserver_t fsrv_var = {0};
afl_forkserver_t *fsrv = &fsrv_var;
afl_fsrv_init(fsrv);
+ map_size = get_map_size();
+ fsrv->map_size = map_size;
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
@@ -704,8 +562,8 @@ int main(int argc, char **argv_orig, char **envp) {
case 'o':
- if (fsrv->out_file) FATAL("Multiple -o options not supported");
- fsrv->out_file = optarg;
+ if (out_file) FATAL("Multiple -o options not supported");
+ out_file = optarg;
break;
case 'm': {
@@ -715,6 +573,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1;
+ if (!optarg) FATAL("Wrong usage of -m");
+
if (!strcmp(optarg, "none")) {
fsrv->mem_limit = 0;
@@ -758,6 +618,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (timeout_given) FATAL("Multiple -t options not supported");
timeout_given = 1;
+ if (!optarg) FATAL("Wrong usage of -t");
+
if (strcmp(optarg, "none")) {
fsrv->exec_tmout = atoi(optarg);
@@ -798,10 +660,10 @@ int main(int argc, char **argv_orig, char **envp) {
case 'Q':
- if (qemu_mode) FATAL("Multiple -Q options not supported");
+ if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported");
if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU;
- qemu_mode = 1;
+ fsrv->qemu_mode = 1;
break;
case 'U':
@@ -815,7 +677,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'W': /* Wine+QEMU mode */
if (use_wine) FATAL("Multiple -W options not supported");
- qemu_mode = 1;
+ fsrv->qemu_mode = 1;
use_wine = 1;
if (!mem_limit_given) fsrv->mem_limit = 0;
@@ -852,17 +714,17 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (optind == argc || !fsrv->out_file) usage(argv[0]);
+ if (optind == argc || !out_file) usage(argv[0]);
check_environment_vars(envp);
sharedmem_t shm = {0};
- fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+ fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
setup_signal_handlers();
- set_up_environment();
+ set_up_environment(fsrv);
- find_binary(fsrv, argv[optind]);
+ fsrv->target_path = find_binary(argv[optind]);
if (!quiet_mode) {
@@ -885,7 +747,7 @@ int main(int argc, char **argv_orig, char **envp) {
for (i = optind; i < argc; i++)
if (strcmp(argv[i], "@@") == 0) arg_offset = i;
- if (qemu_mode) {
+ if (fsrv->qemu_mode) {
if (use_wine)
use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
@@ -903,7 +765,7 @@ int main(int argc, char **argv_orig, char **envp) {
DIR * dir_in, *dir_out;
struct dirent *dir_ent;
int done = 0;
- u8 infile[4096], outfile[4096];
+ u8 infile[PATH_MAX], outfile[PATH_MAX];
#if !defined(DT_REG)
struct stat statbuf;
#endif
@@ -913,9 +775,9 @@ int main(int argc, char **argv_orig, char **envp) {
if (!(dir_in = opendir(in_dir))) PFATAL("cannot open directory %s", in_dir);
- if (!(dir_out = opendir(fsrv->out_file)))
- if (mkdir(fsrv->out_file, 0700))
- PFATAL("cannot create output directory %s", fsrv->out_file);
+ if (!(dir_out = opendir(out_file)))
+ if (mkdir(out_file, 0700))
+ PFATAL("cannot create output directory %s", out_file);
u8 *use_dir = ".";
@@ -930,7 +792,7 @@ int main(int argc, char **argv_orig, char **envp) {
unlink(stdin_file);
atexit(at_exit_handler);
fsrv->out_fd = open(stdin_file, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+ if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", out_file);
if (arg_offset && argv[arg_offset] != stdin_file) {
@@ -951,7 +813,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
- afl_fsrv_start(fsrv, use_argv);
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
while (done == 0 && (dir_ent = readdir(dir_in))) {
@@ -968,12 +831,11 @@ int main(int argc, char **argv_orig, char **envp) {
if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue;
#endif
- snprintf(outfile, sizeof(outfile), "%s/%s", fsrv->out_file,
- dir_ent->d_name);
+ snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name);
if (read_file(infile)) {
- run_target_forkserver(fsrv, use_argv, in_data, in_len);
+ showmap_run_target_forkserver(fsrv, use_argv, in_data, in_len);
ck_free(in_data);
tcnt = write_results_to_file(fsrv, outfile);
@@ -981,15 +843,15 @@ 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);
- closedir(dir_out);
+ if (dir_out) closedir(dir_out);
} else {
- run_target(fsrv, use_argv);
- tcnt = write_results(fsrv);
+ showmap_run_target(fsrv, use_argv);
+ tcnt = write_results_to_file(fsrv, out_file);
}
@@ -997,7 +859,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (!tcnt) FATAL("No instrumentation detected" cRST);
OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST,
- tcnt, highest, total, fsrv->out_file);
+ tcnt, highest, total, out_file);
}
@@ -1011,7 +873,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);
@@ -1019,6 +881,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (stdin_file) ck_free(stdin_file);
argv_cpy_free(argv);
+ if (fsrv->qemu_mode) free(use_argv[2]);
exit(ret);
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 30e76d42..dab2a417 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -8,7 +8,8 @@
Now maintained by Marc Heuse <mh@mh-sec.de>,
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Andrea Fioraldi <andreafioraldi@gmail.com> and
+ Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
@@ -60,19 +61,19 @@
static u8 *mask_bitmap; /* Mask for trace bits (-B) */
-u8 *in_file, /* Minimizer input test case */
- *output_file; /* Minimizer output file */
+static u8 *in_file, /* Minimizer input test case */
+ *out_file, *output_file; /* Minimizer output file */
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 */
+ missed_paths, /* Misses due to exec path diffs */
+ map_size = MAP_SIZE;
-u8 crash_mode, /* Crash-centric mode? */
+static u8 crash_mode, /* Crash-centric mode? */
hang_mode, /* Minimize as long as it hangs */
exit_crash, /* Treat non-zero exit as crash? */
edges_only, /* Ignore hit counts? */
@@ -80,8 +81,6 @@ u8 crash_mode, /* Crash-centric mode? */
static volatile u8 stop_soon; /* Ctrl-C pressed? */
-static u8 qemu_mode;
-
/*
* forkserver section
*/
@@ -103,9 +102,28 @@ static const u8 count_class_lookup[256] = {
};
-static void classify_counts(u8 *mem) {
+/* Apply mask to classified bitmap (if set). */
+
+static void apply_mask(u32 *mem, u32 *mask) {
+
+ u32 i = (map_size >> 2);
+
+ if (!mask) return;
+
+ while (i--) {
+
+ *mem &= ~*mask;
+ mem++;
+ mask++;
+
+ }
+
+}
+
+static void classify_counts(afl_forkserver_t *fsrv) {
- u32 i = MAP_SIZE;
+ u8 *mem = fsrv->trace_bits;
+ u32 i = map_size;
if (edges_only) {
@@ -129,30 +147,12 @@ static void classify_counts(u8 *mem) {
}
-/* Apply mask to classified bitmap (if set). */
-
-static void apply_mask(u32 *mem, u32 *mask) {
-
- u32 i = (MAP_SIZE >> 2);
-
- if (!mask) return;
-
- while (i--) {
-
- *mem &= ~*mask;
- mem++;
- mask++;
-
- }
-
-}
-
/* See if any bytes are set in the bitmap. */
static inline u8 anything_set(afl_forkserver_t *fsrv) {
u32 *ptr = (u32 *)fsrv->trace_bits;
- u32 i = (MAP_SIZE >> 2);
+ u32 i = (map_size >> 2);
while (i--)
if (*(ptr++)) return 1;
@@ -212,117 +212,18 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) {
}
-/* Write modified data to file for testing. If use_stdin is clear, the old file
- is unlinked and a new one is created. Otherwise, out_fd is rewound and
- truncated. */
-
-static void write_to_testcase(afl_forkserver_t *fsrv, void *mem, u32 len) {
-
- s32 fd = fsrv->out_fd;
-
- if (!fsrv->use_stdin) {
-
- unlink(fsrv->out_file); /* Ignore errors. */
-
- fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
-
- if (fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
-
- } else
-
- lseek(fd, 0, SEEK_SET);
-
- ck_write(fd, mem, len, fsrv->out_file);
-
- if (fsrv->use_stdin) {
-
- if (ftruncate(fd, len)) PFATAL("ftruncate() failed");
- lseek(fd, 0, SEEK_SET);
-
- } else
-
- close(fd);
-
-}
-
/* Execute target application. Returns 0 if the changes are a dud, or
1 if they should be kept. */
-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, 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?)");
-
- }
+static u8 tmin_run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
+ u8 first_run) {
- if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)");
+ afl_fsrv_write_to_testcase(fsrv, mem, len);
- /* Configure timeout, wait for child, cancel timeout. */
+ fsrv_run_result_t ret =
+ afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon);
- 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]);
-
- if (!hang_mode) {
-
- classify_counts(fsrv->trace_bits);
- apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
-
- }
-
- total_execs++;
+ if (ret == FSRV_RUN_ERROR) FATAL("Couldn't run child");
if (stop_soon) {
@@ -336,25 +237,20 @@ 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) {
- missed_crashes++;
-
- } else {
-
- missed_hangs++;
+ case FSRV_RUN_TMOUT: return 1;
+ case FSRV_RUN_CRASH: missed_crashes++; return 0;
+ default: missed_hangs++; return 0;
}
- return 0;
-
}
- if (fsrv->child_timed_out) {
+ classify_counts(fsrv);
+ apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap);
+
+ if (ret == FSRV_RUN_TMOUT) {
missed_hangs++;
return 0;
@@ -363,9 +259,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;
@@ -393,7 +287,9 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len,
}
- cksum = hash32(fsrv->trace_bits, 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;
@@ -441,7 +337,7 @@ static void minimize(afl_forkserver_t *fsrv, char **argv) {
memset(tmp_buf + set_pos, '0', use_len);
u8 res;
- res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+ res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
if (res) {
@@ -514,7 +410,7 @@ next_del_blksize:
/* Tail */
memcpy(tmp_buf + del_pos, in_data + del_pos + del_len, tail_len);
- res = run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0);
+ res = tmin_run_target(fsrv, argv, tmp_buf, del_pos + tail_len, 0);
if (res) {
@@ -577,7 +473,7 @@ next_del_blksize:
for (r = 0; r < in_len; r++)
if (tmp_buf[r] == i) tmp_buf[r] = '0';
- res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+ res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
if (res) {
@@ -613,7 +509,7 @@ next_del_blksize:
if (orig == '0') continue;
tmp_buf[i] = '0';
- res = run_target(fsrv, argv, tmp_buf, in_len, 0);
+ res = tmin_run_target(fsrv, argv, tmp_buf, in_len, 0);
if (res) {
@@ -642,25 +538,27 @@ 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,
- missed_paths, missed_crashes);
+ ((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1),
+ fsrv->total_execs, missed_paths, missed_crashes);
return;
}
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,
- missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs);
+ ((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);
}
@@ -683,7 +581,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) PFATAL("Unable to open /dev/null");
- if (!fsrv->out_file) {
+ if (!out_file) {
u8 *use_dir = ".";
@@ -694,15 +592,15 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
}
- fsrv->out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
+ out_file = alloc_printf("%s/.afl-tmin-temp-%u", use_dir, getpid());
}
- unlink(fsrv->out_file);
+ unlink(out_file);
- fsrv->out_fd = open(fsrv->out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
+ fsrv->out_fd = open(out_file, O_RDWR | O_CREAT | O_EXCL, 0600);
- if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", fsrv->out_file);
+ if (fsrv->out_fd < 0) PFATAL("Unable to create '%s'", out_file);
/* Set sane defaults... */
@@ -746,7 +644,7 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
if (get_afl_env("AFL_PRELOAD")) {
- if (qemu_mode) {
+ if (fsrv->qemu_mode) {
u8 *qemu_preload = getenv("QEMU_SET_ENV");
u8 *afl_preload = getenv("AFL_PRELOAD");
@@ -843,7 +741,9 @@ static void usage(u8 *argv0) {
" (must contain abort_on_error=1 and symbolize=0)\n"
"MSAN_OPTIONS: custom settings for MSAN\n"
" (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n"
- "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
+ "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
+ " the target was compiled for\n"
+ "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
@@ -852,76 +752,6 @@ static void usage(u8 *argv0) {
}
-/* Find binary. */
-
-static void find_binary(afl_forkserver_t *fsrv, u8 *fname) {
-
- u8 * env_path = 0;
- struct stat st;
-
- if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
-
- fsrv->target_path = ck_strdup(fname);
-
- if (stat(fsrv->target_path, &st) || !S_ISREG(st.st_mode) ||
- !(st.st_mode & 0111) || st.st_size < 4)
- FATAL("Program '%s' not found or not executable", fname);
-
- } else {
-
- while (env_path) {
-
- u8 *cur_elem, *delim = strchr(env_path, ':');
-
- if (delim) {
-
- cur_elem = ck_alloc(delim - env_path + 1);
- memcpy(cur_elem, env_path, delim - env_path);
- delim++;
-
- } else
-
- cur_elem = ck_strdup(env_path);
-
- env_path = delim;
-
- if (cur_elem[0])
- fsrv->target_path = alloc_printf("%s/%s", cur_elem, fname);
- else
- fsrv->target_path = ck_strdup(fname);
-
- ck_free(cur_elem);
-
- if (!stat(fsrv->target_path, &st) && S_ISREG(st.st_mode) &&
- (st.st_mode & 0111) && st.st_size >= 4)
- break;
-
- ck_free(fsrv->target_path);
- fsrv->target_path = NULL;
-
- }
-
- if (!fsrv->target_path)
- FATAL("Program '%s' not found or not executable", fname);
-
- }
-
-}
-
-/* Read mask bitmap from file. This is for the -B option. */
-
-static void read_bitmap(u8 *fname) {
-
- s32 fd = open(fname, O_RDONLY);
-
- if (fd < 0) PFATAL("Unable to open '%s'", fname);
-
- ck_read(fd, mask_bitmap, MAP_SIZE, fname);
-
- close(fd);
-
-}
-
/* Main entry point */
int main(int argc, char **argv_orig, char **envp) {
@@ -935,6 +765,8 @@ int main(int argc, char **argv_orig, char **envp) {
afl_forkserver_t fsrv_var = {0};
afl_forkserver_t *fsrv = &fsrv_var;
afl_fsrv_init(fsrv);
+ map_size = get_map_size();
+ fsrv->map_size = map_size;
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
@@ -958,9 +790,9 @@ int main(int argc, char **argv_orig, char **envp) {
case 'f':
- if (fsrv->out_file) FATAL("Multiple -f options not supported");
+ if (out_file) FATAL("Multiple -f options not supported");
fsrv->use_stdin = 0;
- fsrv->out_file = optarg;
+ out_file = optarg;
break;
case 'e':
@@ -984,6 +816,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1;
+ if (!optarg) FATAL("Wrong usage of -m");
+
if (!strcmp(optarg, "none")) {
fsrv->mem_limit = 0;
@@ -1020,6 +854,8 @@ int main(int argc, char **argv_orig, char **envp) {
if (timeout_given) FATAL("Multiple -t options not supported");
timeout_given = 1;
+ if (!optarg) FATAL("Wrong usage of -t");
+
fsrv->exec_tmout = atoi(optarg);
if (fsrv->exec_tmout < 10 || optarg[0] == '-')
@@ -1029,10 +865,10 @@ int main(int argc, char **argv_orig, char **envp) {
case 'Q':
- if (qemu_mode) FATAL("Multiple -Q options not supported");
+ if (fsrv->qemu_mode) FATAL("Multiple -Q options not supported");
if (!mem_limit_given) fsrv->mem_limit = MEM_LIMIT_QEMU;
- qemu_mode = 1;
+ fsrv->qemu_mode = 1;
break;
case 'U':
@@ -1046,7 +882,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'W': /* Wine+QEMU mode */
if (use_wine) FATAL("Multiple -W options not supported");
- qemu_mode = 1;
+ fsrv->qemu_mode = 1;
use_wine = 1;
if (!mem_limit_given) fsrv->mem_limit = 0;
@@ -1079,8 +915,8 @@ int main(int argc, char **argv_orig, char **envp) {
to be useful. */
if (mask_bitmap) FATAL("Multiple -B options not supported");
- mask_bitmap = ck_alloc(MAP_SIZE);
- read_bitmap(optarg);
+ mask_bitmap = ck_alloc(map_size);
+ read_bitmap(optarg, mask_bitmap, map_size);
break;
case 'h':
@@ -1097,17 +933,17 @@ int main(int argc, char **argv_orig, char **envp) {
check_environment_vars(envp);
sharedmem_t shm = {0};
- fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0);
+ fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment(fsrv);
- find_binary(fsrv, argv[optind]);
- detect_file_args(argv + optind, fsrv->out_file, &fsrv->use_stdin);
+ fsrv->target_path = find_binary(argv[optind]);
+ detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
- if (qemu_mode) {
+ if (fsrv->qemu_mode) {
if (use_wine)
use_argv = get_wine_argv(argv[0], &fsrv->target_path, argc - optind,
@@ -1133,20 +969,21 @@ int main(int argc, char **argv_orig, char **envp) {
read_initial_file();
- afl_fsrv_start(fsrv, use_argv);
+ afl_fsrv_start(fsrv, use_argv, &stop_soon,
+ get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0);
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : "");
- run_target(fsrv, use_argv, in_data, in_len, 1);
+ tmin_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.");
@@ -1174,9 +1011,9 @@ int main(int argc, char **argv_orig, char **envp) {
ACTF("Writing output to '%s'...", output_file);
- unlink(fsrv->out_file);
- if (fsrv->out_file) ck_free(fsrv->out_file);
- fsrv->out_file = NULL;
+ unlink(out_file);
+ if (out_file) ck_free(out_file);
+ out_file = NULL;
close(write_to_file(output_file, in_data, in_len));
diff --git a/src/third_party/libradamsa/libradamsa.c b/src/third_party/libradamsa/libradamsa.c
index fe91594e..4f5515e5 100644
--- a/src/third_party/libradamsa/libradamsa.c
+++ b/src/third_party/libradamsa/libradamsa.c
@@ -1841,6 +1841,8 @@ static const unsigned char heap[] = {2,3,4,105,111,116,97,2,3,7,112,97,116,116,1
#include <stdio.h>
#include <netdb.h>
+#include "./radamsa.h"
+
#ifndef EMULTIHOP
#define EMULTIHOP -1
#endif
@@ -2155,17 +2157,17 @@ static word *gc(int size, word *regs) {
/*** OS Interaction and Helpers ***/
-static void signal_handler(int signal) {
- switch (signal) {
- case SIGINT:
- breaked |= 2;
- break;
- case SIGPIPE:
- break; /* can cause loop when reporting errors */
- default:
- breaked |= 4;
- }
-}
+//static void signal_handler(int signal) {
+// switch (signal) {
+// case SIGINT:
+// breaked |= 2;
+// break;
+// case SIGPIPE:
+// break; /* can cause loop when reporting errors */
+// default:
+// breaked |= 4;
+// }
+//}
/* list length, no overflow or valid termination checks */
static uint llen(word *ptr) {
@@ -2176,8 +2178,8 @@ static uint llen(word *ptr) {
}
return len;
}
-
-static void set_signal_handler() {
+/*
+static void set_signal_handler(void) {
struct sigaction sa;
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
@@ -2185,7 +2187,7 @@ static void set_signal_handler() {
sigaction(SIGINT, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
}
-
+*/
static word mkpair(word h, word a, word d) {
word *pair;
allocate(3, pair);
@@ -2312,7 +2314,7 @@ static word prim_set(word wptr, hval pos, word val) {
return (word) new;
}
-static void setdown() {
+static void setdown(void) {
tcsetattr(0, TCSANOW, &tsettings); /* return stdio settings */
}
@@ -30683,7 +30685,7 @@ static void heap_metrics(int *rwords, int *rnobjs) {
get_obj_metrics(rwords, rnobjs);
hp = hp_start;
}
-
+/*
static void read_heap(const char *path) {
struct stat st;
off_t pos = 0;
@@ -30703,25 +30705,26 @@ static void read_heap(const char *path) {
} while (n && (pos += n) < st.st_size);
close(fd);
}
+*/
/* find a fasl image source to *hp or exit */
-static void find_heap(int *nargs, char ***argv, int *nobjs, int *nwords) {
- file_heap = NULL;
- if ((word)heap == 0) {
+//static void find_heap(int *nargs, char ***argv, int *nobjs, int *nwords) {
+// file_heap = NULL;
+// if ((word)heap == 0) {
/* if no preloaded heap, try to load it from first vm arg */
- if (*nargs < 2)
- exit(1);
- read_heap(argv[0][1]);
- ++*argv;
- --*nargs;
- hp = file_heap;
- if (*hp == '#')
- while (*hp++ != '\n');
- } else {
- hp = heap; /* builtin heap */
- }
- heap_metrics(nwords, nobjs);
-}
+// if (*nargs < 2)
+// exit(1);
+// read_heap(argv[0][1]);
+// ++*argv;
+// --*nargs;
+// hp = file_heap;
+// if (*hp == '#')
+// while (*hp++ != '\n');
+// } else {
+// hp = heap; /* builtin heap */
+// }
+// heap_metrics(nwords, nobjs);
+//}
static word *decode_fasl(uint nobjs) {
word *ptrs;
@@ -30744,7 +30747,7 @@ static word *load_heap(uint nobjs) {
free(file_heap);
return entry;
}
-
+/*
static void setup(int nwords, int nobjs) {
tcgetattr(0, &tsettings);
state = IFALSE;
@@ -30757,7 +30760,7 @@ static void setup(int nwords, int nobjs) {
memend = memstart + nwords - MEMPAD;
}
-int secondary(int nargs, char **argv) {
+static int secondary(int nargs, char **argv) {
word *prog;
int rval, nobjs=0, nwords=0;
find_heap(&nargs, &argv, &nobjs, &nwords);
@@ -30772,8 +30775,9 @@ int secondary(int nargs, char **argv) {
}
return 127;
}
+*/
-void radamsa_init() {
+void radamsa_init(void) {
int nobjs=0, nwords=0;
hp = (byte *) &heap; /* builtin heap */
state = IFALSE;
@@ -30787,7 +30791,7 @@ void radamsa_init() {
}
/* bvec → value library call test with preserved state */
-word library_call(word val) {
+static word library_call(word val) {
word program_state = state;
word res;
state = IFALSE;
@@ -30798,7 +30802,8 @@ word library_call(word val) {
return res;
}
-size_t list_length(word lispval) {
+/*
+static size_t list_length(word lispval) {
size_t l = 0;
while(lispval != INULL) {
lispval = G(lispval, 2);
@@ -30806,8 +30811,9 @@ size_t list_length(word lispval) {
}
return l;
}
+*/
-size_t copy_list(uint8_t *ptr, word lispval, size_t max) {
+static size_t copy_list(uint8_t *ptr, word lispval, size_t max) {
size_t n = 0;
while(pairp((word)lispval) && max-- && lispval != INULL) {
*ptr++ = 255 & immval(G(lispval, 1)); // *ptr++ = car(list)
diff --git a/src/third_party/libradamsa/radamsa.h b/src/third_party/libradamsa/radamsa.h
index d54fa2ec..073599da 100644
--- a/src/third_party/libradamsa/radamsa.h
+++ b/src/third_party/libradamsa/radamsa.h
@@ -1,15 +1,13 @@
#include <inttypes.h>
#include <stddef.h>
-extern void radamsa_init();
+void radamsa_init(void);
-extern size_t radamsa(uint8_t *ptr, size_t len,
- uint8_t *target, size_t max,
+size_t radamsa(uint8_t *ptr, size_t len,
+ uint8_t *target, size_t max,
unsigned int seed);
-extern size_t radamsa_inplace(uint8_t *ptr,
- size_t len,
- size_t max,
+size_t radamsa_inplace(uint8_t *ptr,
+ size_t len,
+ size_t max,
unsigned int seed);
-
-