AFL_CRASH_EXITCODE env var added, u8->bool

This commit is contained in:
Dominik Maier
2020-12-03 14:43:06 +01:00
parent 0f803c63df
commit a2e2fae840
16 changed files with 152 additions and 37 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@
*.pyc *.pyc
*.dSYM *.dSYM
as as
a.out
ld ld
in in
out out

View File

@ -116,11 +116,12 @@ function usage() {
"For additional tips, please consult README.md\n" \ "For additional tips, please consult README.md\n" \
"\n" \ "\n" \
"Environment variables used:\n" \ "Environment variables used:\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n" \
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n" \
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n" \
"AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \ "AFL_KEEP_TRACES: leave the temporary <out_dir>/.traces directory\n" \
"AFL_PATH: path for the afl-showmap binary\n" \ "AFL_PATH: path for the afl-showmap binary\n" \
"AFL_SKIP_BIN_CHECK: skip check for target binary\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" \
"AFL_ALLOW_TMP: allow unsafe use of input/output directories under {/var}/tmp\n"
"AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the target to come up, initially\n"
exit 1 exit 1
} }

View File

@ -60,8 +60,10 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
- Our afl++ Grammar-Mutator is now better integrated into custom_mutators/ - Our afl++ Grammar-Mutator is now better integrated into custom_mutators/
- added INTROSPECTION support for custom modules - added INTROSPECTION support for custom modules
- python fuzz function was not optional, fixed - python fuzz function was not optional, fixed
- unicornafl synced with upstream (arm64 fix, better rust bindings) - some python mutator speed improvements
- unicornafl synced with upstream version 1.02 (fixes, better rust bindings)
- renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD - renamed AFL_DEBUG_CHILD_OUTPUT to AFL_DEBUG_CHILD
- added AFL_CRASH_EXITCODE env variable to treat a child exitcode as crash
### Version ++2.68c (release) ### Version ++2.68c (release)

View File

@ -428,6 +428,13 @@ checks or alter some of the more exotic semantics of the tool:
matches your StatsD server. matches your StatsD server.
Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`. Available flavors are `dogstatsd`, `librato`, `signalfx` and `influxdb`.
- Setting `AFL_CRASH_EXITCODE` sets the exit code afl treats as crash.
For example, if `AFL_CRASH_EXITCODE='-1'` is set, each input resulting
in an `-1` return code (i.e. `exit(-1)` got called), will be treated
as if a crash had ocurred.
This may be beneficial if you look for higher-level faulty conditions in which your
target still exits gracefully.
- Outdated environment variables that are not supported anymore: - Outdated environment variables that are not supported anymore:
`AFL_DEFER_FORKSRV` `AFL_DEFER_FORKSRV`
`AFL_PERSISTENT` `AFL_PERSISTENT`

View File

@ -144,8 +144,8 @@ struct queue_entry {
u8 *fname; /* File name for the test case */ u8 *fname; /* File name for the test case */
u32 len; /* Input length */ u32 len; /* Input length */
u8 cal_failed, /* Calibration failed? */ u8 cal_failed; /* Calibration failed? */
trim_done, /* Trimmed? */ bool trim_done, /* Trimmed? */
was_fuzzed, /* historical, but needed for MOpt */ was_fuzzed, /* historical, but needed for MOpt */
passed_det, /* Deterministic stages passed? */ passed_det, /* Deterministic stages passed? */
has_new_cov, /* Triggers new coverage? */ has_new_cov, /* Triggers new coverage? */
@ -368,7 +368,8 @@ typedef struct afl_env_vars {
u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path,
*afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_skip_crashes, *afl_preload,
*afl_max_det_extras, *afl_statsd_host, *afl_statsd_port, *afl_max_det_extras, *afl_statsd_host, *afl_statsd_port,
*afl_statsd_tags_flavor, *afl_testcache_size, *afl_testcache_entries; *afl_crash_exitcode, *afl_statsd_tags_flavor, *afl_testcache_size,
*afl_testcache_entries;
} afl_env_vars_t; } afl_env_vars_t;

View File

@ -38,7 +38,7 @@
#define STRINGIFY_VAL_SIZE_MAX (16) #define STRINGIFY_VAL_SIZE_MAX (16)
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin); void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin);
void check_environment_vars(char **env); void check_environment_vars(char **env);
char **argv_cpy_dup(int argc, char **argv); char **argv_cpy_dup(int argc, char **argv);

View File

@ -32,6 +32,7 @@ static char *afl_environment_variables[] = {
"AFL_CODE_START", "AFL_CODE_START",
"AFL_COMPCOV_BINNAME", "AFL_COMPCOV_BINNAME",
"AFL_COMPCOV_LEVEL", "AFL_COMPCOV_LEVEL",
"AFL_CRASH_EXITCODE",
"AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_MUTATOR_ONLY",
"AFL_CXX", "AFL_CXX",

View File

@ -37,9 +37,7 @@ typedef struct afl_forkserver {
/* a program that includes afl-forkserver needs to define these */ /* a program that includes afl-forkserver needs to define these */
u8 uses_asan; /* Target uses ASAN? */
u8 *trace_bits; /* SHM with instrumentation bitmap */ u8 *trace_bits; /* SHM with instrumentation bitmap */
u8 use_stdin; /* use stdin for sending data */
s32 fsrv_pid, /* PID of the fork server */ s32 fsrv_pid, /* PID of the fork server */
child_pid, /* PID of the fuzzed program */ child_pid, /* PID of the fuzzed program */
@ -53,8 +51,6 @@ typedef struct afl_forkserver {
fsrv_ctl_fd, /* Fork server control pipe (write) */ fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */ fsrv_st_fd; /* Fork server status pipe (read) */
u8 no_unlink; /* do not unlink cur_input */
u32 exec_tmout; /* Configurable exec timeout (ms) */ u32 exec_tmout; /* Configurable exec timeout (ms) */
u32 init_tmout; /* Configurable init timeout (ms) */ u32 init_tmout; /* Configurable init timeout (ms) */
u32 map_size; /* map size used by the target */ u32 map_size; /* map size used by the target */
@ -73,13 +69,22 @@ typedef struct afl_forkserver {
u8 last_kill_signal; /* Signal that killed the child */ u8 last_kill_signal; /* Signal that killed the child */
u8 use_shmem_fuzz; /* use shared mem for test cases */ bool use_shmem_fuzz; /* use shared mem for test cases */
u8 support_shmem_fuzz; /* set by afl-fuzz */ bool support_shmem_fuzz; /* set by afl-fuzz */
u8 use_fauxsrv; /* Fauxsrv for non-forking targets? */ bool use_fauxsrv; /* Fauxsrv for non-forking targets? */
u8 qemu_mode; /* if running in qemu mode or not */ bool qemu_mode; /* if running in qemu mode or not */
bool use_stdin; /* use stdin for sending data */
bool no_unlink; /* do not unlink cur_input */
bool uses_asan; /* Target uses ASAN? */
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
u8 crash_exitcode; /* The crash exitcode specified */
u32 *shmem_fuzz_len; /* length of the fuzzing test case */ u32 *shmem_fuzz_len; /* length of the fuzzing test case */

View File

@ -78,9 +78,9 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
static s32 dev_null_fd = -1; /* FD to /dev/null */ static s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 edges_only, /* Ignore hit counts? */ static bool edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */ use_hex_offsets, /* Show hex offsets? */
use_stdin = 1; /* Use stdin for program input? */ use_stdin = true; /* Use stdin for program input? */
static volatile u8 stop_soon, /* Ctrl-C pressed? */ static volatile u8 stop_soon, /* Ctrl-C pressed? */
child_timed_out; /* Child timed out? */ child_timed_out; /* Child timed out? */

View File

@ -46,7 +46,7 @@ u8 be_quiet = 0;
u8 *doc_path = ""; u8 *doc_path = "";
u8 last_intr = 0; u8 last_intr = 0;
void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) { void detect_file_args(char **argv, u8 *prog_in, bool *use_stdin) {
u32 i = 0; u32 i = 0;
u8 cwd[PATH_MAX]; u8 cwd[PATH_MAX];
@ -63,7 +63,7 @@ void detect_file_args(char **argv, u8 *prog_in, u8 *use_stdin) {
if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); } if (!prog_in) { FATAL("@@ syntax is not supported by this tool."); }
*use_stdin = 0; *use_stdin = false;
if (prog_in[0] != 0) { // not afl-showmap special case if (prog_in[0] != 0) { // not afl-showmap special case

View File

@ -76,8 +76,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->dev_urandom_fd = -1; fsrv->dev_urandom_fd = -1;
/* Settings */ /* Settings */
fsrv->use_stdin = 1; fsrv->use_stdin = true;
fsrv->no_unlink = 0; fsrv->no_unlink = false;
fsrv->exec_tmout = EXEC_TIMEOUT; fsrv->exec_tmout = EXEC_TIMEOUT;
fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT; fsrv->init_tmout = EXEC_TIMEOUT * FORK_WAIT_MULT;
fsrv->mem_limit = MEM_LIMIT; fsrv->mem_limit = MEM_LIMIT;
@ -86,8 +86,11 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
/* exec related stuff */ /* exec related stuff */
fsrv->child_pid = -1; fsrv->child_pid = -1;
fsrv->map_size = get_map_size(); fsrv->map_size = get_map_size();
fsrv->use_fauxsrv = 0; fsrv->use_fauxsrv = false;
fsrv->last_run_timed_out = 0; fsrv->last_run_timed_out = false;
fsrv->uses_crash_exitcode = false;
fsrv->uses_asan = false;
fsrv->init_child_func = fsrv_exec_child; fsrv->init_child_func = fsrv_exec_child;
@ -109,6 +112,8 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->dev_urandom_fd = from->dev_urandom_fd; fsrv_to->dev_urandom_fd = from->dev_urandom_fd;
fsrv_to->out_fd = from->out_fd; // not sure this is a good idea fsrv_to->out_fd = from->out_fd; // not sure this is a good idea
fsrv_to->no_unlink = from->no_unlink; fsrv_to->no_unlink = from->no_unlink;
fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
fsrv_to->crash_exitcode = from->crash_exitcode;
// These are forkserver specific. // These are forkserver specific.
fsrv_to->out_dir_fd = -1; fsrv_to->out_dir_fd = -1;
@ -1136,10 +1141,13 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
} }
/* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and /* MSAN in uses_asan mode uses a special exit code as it doesn't support
must use a special exit code. */ abort_on_error.
On top, a user may specify a custom AFL_CRASH_EXITCODE. Handle both here. */
if (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) { if ((fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
(fsrv->uses_crash_exitcode &&
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode)) {
fsrv->last_kill_signal = 0; fsrv->last_kill_signal = 0;
return FSRV_RUN_CRASH; return FSRV_RUN_CRASH;

View File

@ -868,7 +868,19 @@ void perform_dry_run(afl_state_t *afl) {
if (skip_crashes) { if (skip_crashes) {
if (afl->fsrv.uses_crash_exitcode) {
WARNF(
"Test case results in a crash or AFL_CRASH_EXITCODE %d "
"(skipping)",
(int)(s8)afl->fsrv.crash_exitcode);
} else {
WARNF("Test case results in a crash (skipping)"); WARNF("Test case results in a crash (skipping)");
}
q->cal_failed = CAL_CHANCES; q->cal_failed = CAL_CHANCES;
++cal_failures; ++cal_failures;
break; break;
@ -954,8 +966,19 @@ void perform_dry_run(afl_state_t *afl) {
#undef MSG_ULIMIT_USAGE #undef MSG_ULIMIT_USAGE
#undef MSG_FORK_ON_APPLE #undef MSG_FORK_ON_APPLE
if (afl->fsrv.uses_crash_exitcode) {
WARNF(
"Test case '%s' results in a crash or AFL_CRASH_EXITCODE %d, "
"skipping",
fn, (int)(s8)afl->fsrv.crash_exitcode);
} else {
WARNF("Test case '%s' results in a crash, skipping", fn); WARNF("Test case '%s' results in a crash, skipping", fn);
}
/* Remove from fuzzing queue but keep for splicing */ /* Remove from fuzzing queue but keep for splicing */
struct queue_entry *p = afl->queue; struct queue_entry *p = afl->queue;

View File

@ -394,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_statsd_tags_flavor = afl->afl_env.afl_statsd_tags_flavor =
(u8 *)get_afl_env(afl_environment_variables[i]); (u8 *)get_afl_env(afl_environment_variables[i]);
} else if (!strncmp(env, "AFL_CRASH_EXITCODE",
afl_environment_variable_len)) {
afl->afl_env.afl_crash_exitcode =
(u8 *)get_afl_env(afl_environment_variables[i]);
} }
} else { } else {

View File

@ -26,6 +26,7 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "cmplog.h" #include "cmplog.h"
#include <limits.h> #include <limits.h>
#include <stdlib.h>
#ifndef USEMMAP #ifndef USEMMAP
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -165,6 +166,7 @@ static void usage(u8 *argv0, int more_help) {
"AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n"
"AFL_BENCH_JUST_ONE: run the target just once\n" "AFL_BENCH_JUST_ONE: run the target just once\n"
"AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n"
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
"AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\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_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n"
"AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n" "AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
@ -702,7 +704,7 @@ int main(int argc, char **argv_orig, char **envp) {
case 'N': /* Unicorn mode */ case 'N': /* Unicorn mode */
if (afl->no_unlink) { FATAL("Multiple -N options not supported"); } if (afl->no_unlink) { FATAL("Multiple -N options not supported"); }
afl->fsrv.no_unlink = afl->no_unlink = 1; afl->fsrv.no_unlink = (afl->no_unlink = true);
break; break;
@ -1135,6 +1137,23 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (afl->afl_env.afl_crash_exitcode) {
long exitcode = strtol(afl->afl_env.afl_crash_exitcode, NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
afl->afl_env.afl_crash_exitcode);
}
afl->fsrv.uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
afl->fsrv.crash_exitcode = (u8)exitcode;
}
if (afl->non_instrumented_mode == 2 && afl->no_forkserver) { if (afl->non_instrumented_mode == 2 && afl->no_forkserver) {
FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive"); FATAL("AFL_DUMB_FORKSRV and AFL_NO_FORKSRV are mutually exclusive");
@ -1486,9 +1505,12 @@ int main(int argc, char **argv_orig, char **envp) {
cull_queue(afl); cull_queue(afl);
if (!afl->pending_not_fuzzed) if (!afl->pending_not_fuzzed) {
FATAL("We need at least on valid input seed that does not crash!"); FATAL("We need at least on valid input seed that does not crash!");
}
show_init_stats(afl); show_init_stats(afl);
if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl);

View File

@ -667,6 +667,8 @@ static void usage(u8 *argv0) {
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
"inputs\n" "inputs\n"
"AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n" "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n"
"AFL_CRASH_EXITCODE: optional child exit code to be interpreted as "
"crash\n"
"AFL_DEBUG: enable extra developer output\n" "AFL_DEBUG: enable extra developer output\n"
"AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "AFL_MAP_SIZE: the shared memory size for that target. must be >= the "
"size\n" "size\n"
@ -1090,6 +1092,23 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (getenv("AFL_CRASH_EXITCODE")) {
long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
getenv("AFL_CRASH_EXITCODE"));
}
fsrv->uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
fsrv->crash_exitcode = (u8)exitcode;
}
afl_fsrv_start(fsrv, use_argv, &stop_soon, afl_fsrv_start(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") || (get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT")) get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))

View File

@ -51,6 +51,7 @@
#include <signal.h> #include <signal.h>
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/time.h> #include <sys/time.h>
@ -841,17 +842,17 @@ static void usage(u8 *argv0) {
"For additional tips, please consult %s/README.md.\n\n" "For additional tips, please consult %s/README.md.\n\n"
"Environment variables used:\n" "Environment variables used:\n"
"TMPDIR: directory to use for temporary input files\n" "AFL_CRASH_EXITCODE: optional child exit code to be interpreted as crash\n"
"ASAN_OPTIONS: custom settings for ASAN\n" "AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\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_MAP_SIZE: the shared memory size for that target. must be >= the size\n" "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n"
" the target was compiled for\n" " the target was compiled for\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n" "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n"
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in milliseconds)\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"
"TMPDIR: directory to use for temporary input files\n"
, argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path);
exit(1); exit(1);
@ -1122,6 +1123,23 @@ int main(int argc, char **argv_orig, char **envp) {
} }
if (getenv("AFL_CRASH_EXITCODE")) {
long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
exitcode < -127 || exitcode > 128) {
FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
getenv("AFL_CRASH_EXITCODE"));
}
fsrv->uses_crash_exitcode = true;
// WEXITSTATUS is 8 bit unsigned
fsrv->crash_exitcode = (u8)exitcode;
}
shm_fuzz = ck_alloc(sizeof(sharedmem_t)); shm_fuzz = ck_alloc(sizeof(sharedmem_t));
/* initialize cmplog_mode */ /* initialize cmplog_mode */