mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-15 11:28:08 +00:00
Better handling of exit codes used by sanitzers
This commit is contained in:
@ -247,6 +247,12 @@ CFISAN. You might need to experiment which sanitizers you can combine in a
|
|||||||
target (which means more instances can be run without a sanitized target, which
|
target (which means more instances can be run without a sanitized target, which
|
||||||
is more effective).
|
is more effective).
|
||||||
|
|
||||||
|
Note that some sanitizers (MSAN and LSAN) exit with a particular exit code
|
||||||
|
instead of aborting. afl-fuzz treats these exit codes as a crash when these
|
||||||
|
sanitizers are enabled. If the target uses these exit codes there could be false
|
||||||
|
positives among the saved crashes. LSAN uses exit code 23 and MSAN uses exit
|
||||||
|
code 86.
|
||||||
|
|
||||||
### d) Modifying the target
|
### d) Modifying the target
|
||||||
|
|
||||||
If the target has features that make fuzzing more difficult, e.g., checksums,
|
If the target has features that make fuzzing more difficult, e.g., checksums,
|
||||||
|
@ -137,6 +137,8 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
u8 last_kill_signal; /* Signal that killed the child */
|
u8 last_kill_signal; /* Signal that killed the child */
|
||||||
|
|
||||||
|
u8 last_exit_code; /* Child exit code if counted as a crash */
|
||||||
|
|
||||||
bool use_shmem_fuzz; /* use shared mem for test cases */
|
bool use_shmem_fuzz; /* use shared mem for test cases */
|
||||||
|
|
||||||
bool support_shmem_fuzz; /* set by afl-fuzz */
|
bool support_shmem_fuzz; /* set by afl-fuzz */
|
||||||
@ -155,7 +157,7 @@ typedef struct afl_forkserver {
|
|||||||
|
|
||||||
bool no_unlink; /* do not unlink cur_input */
|
bool no_unlink; /* do not unlink cur_input */
|
||||||
|
|
||||||
bool uses_asan; /* Target uses ASAN? */
|
u8 uses_asan; /* Target uses ASAN/LSAN/MSAN? (bit 0/1/2 respectively) */
|
||||||
|
|
||||||
bool debug; /* debug mode? */
|
bool debug; /* debug mode? */
|
||||||
|
|
||||||
|
@ -258,7 +258,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
|
|||||||
fsrv->last_run_timed_out = false;
|
fsrv->last_run_timed_out = false;
|
||||||
fsrv->debug = false;
|
fsrv->debug = false;
|
||||||
fsrv->uses_crash_exitcode = false;
|
fsrv->uses_crash_exitcode = false;
|
||||||
fsrv->uses_asan = false;
|
fsrv->uses_asan = 0;
|
||||||
|
|
||||||
#ifdef __AFL_CODE_COVERAGE
|
#ifdef __AFL_CODE_COVERAGE
|
||||||
fsrv->persistent_trace_bits = NULL;
|
fsrv->persistent_trace_bits = NULL;
|
||||||
@ -2087,17 +2087,19 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target(
|
|||||||
|
|
||||||
/* Did we crash?
|
/* Did we crash?
|
||||||
In a normal case, (abort) WIFSIGNALED(child_status) will be set.
|
In a normal case, (abort) WIFSIGNALED(child_status) will be set.
|
||||||
MSAN in uses_asan mode uses a special exit code as it doesn't support
|
MSAN & LSAN in uses_asan mode use special exit codes as they doesn't support
|
||||||
abort_on_error. On top, a user may specify a custom AFL_CRASH_EXITCODE.
|
abort_on_error. On top, a user may specify a custom AFL_CRASH_EXITCODE.
|
||||||
Handle all three cases here. */
|
Handle all four cases here. */
|
||||||
|
|
||||||
if (unlikely(
|
if (unlikely(
|
||||||
/* A normal crash/abort */
|
/* A normal crash/abort */
|
||||||
(WIFSIGNALED(fsrv->child_status)) ||
|
(WIFSIGNALED(fsrv->child_status)) ||
|
||||||
/* special handling for msan and lsan */
|
/* special handling for msan */
|
||||||
(fsrv->uses_asan &&
|
((fsrv->uses_asan & 4) &&
|
||||||
(WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
|
WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
|
||||||
WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) ||
|
/* special handling for lsan */
|
||||||
|
((fsrv->uses_asan & 2) &&
|
||||||
|
WEXITSTATUS(fsrv->child_status) == LSAN_ERROR) ||
|
||||||
/* the custom crash_exitcode was returned by the target */
|
/* the custom crash_exitcode was returned by the target */
|
||||||
(fsrv->uses_crash_exitcode &&
|
(fsrv->uses_crash_exitcode &&
|
||||||
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
|
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
|
||||||
@ -2106,6 +2108,10 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target(
|
|||||||
fsrv->last_kill_signal =
|
fsrv->last_kill_signal =
|
||||||
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
|
WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
|
||||||
|
|
||||||
|
/* For a special exit code, set last_exit_code to non-zero */
|
||||||
|
fsrv->last_exit_code =
|
||||||
|
WIFSIGNALED(fsrv->child_status) ? 0 : WEXITSTATUS(fsrv->child_status);
|
||||||
|
|
||||||
#ifdef AFL_PERSISTENT_RECORD
|
#ifdef AFL_PERSISTENT_RECORD
|
||||||
if (unlikely(fsrv->persistent_record)) {
|
if (unlikely(fsrv->persistent_record)) {
|
||||||
|
|
||||||
|
@ -1042,6 +1042,47 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
|
|
||||||
if (afl->crash_mode) { break; }
|
if (afl->crash_mode) { break; }
|
||||||
|
|
||||||
|
const u8 *msg_exit_code = "";
|
||||||
|
|
||||||
|
if (afl->fsrv.uses_asan && !afl->fsrv.last_kill_signal) {
|
||||||
|
|
||||||
|
if ((afl->fsrv.uses_asan & 4) &&
|
||||||
|
afl->fsrv.last_exit_code == MSAN_ERROR) {
|
||||||
|
|
||||||
|
msg_exit_code =
|
||||||
|
" - The test case terminated with the exit code that is "
|
||||||
|
"used by MSAN to\n"
|
||||||
|
" indicate an error. This is counted as a crash by "
|
||||||
|
"afl-fuzz because you\n"
|
||||||
|
" have compiled the target with MSAN enabled. This could "
|
||||||
|
"be a false\n"
|
||||||
|
" positive if the program returns this exit code under "
|
||||||
|
"normal operation.\n"
|
||||||
|
" In that case, either disable MSAN or change the test "
|
||||||
|
"case or program\n"
|
||||||
|
" to avoid generating this exit code.\n\n";
|
||||||
|
|
||||||
|
} else if ((afl->fsrv.uses_asan & 2) &&
|
||||||
|
|
||||||
|
afl->fsrv.last_exit_code == LSAN_ERROR) {
|
||||||
|
|
||||||
|
msg_exit_code =
|
||||||
|
" - The test case terminated with the exit code that is "
|
||||||
|
"used by LSAN to\n"
|
||||||
|
" indicate an error. This is counted as a crash by "
|
||||||
|
"afl-fuzz because you\n"
|
||||||
|
" have compiled the target with LSAN enabled. This could "
|
||||||
|
"be a false\n"
|
||||||
|
" positive if the program returns this exit code under "
|
||||||
|
"normal operation.\n"
|
||||||
|
" In that case, either disable LSAN or change the test "
|
||||||
|
"case or program\n"
|
||||||
|
" to avoid generating this exit code.\n\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (afl->fsrv.mem_limit) {
|
if (afl->fsrv.mem_limit) {
|
||||||
|
|
||||||
u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
|
u8 val_buf[STRINGIFY_VAL_SIZE_MAX];
|
||||||
@ -1056,6 +1097,7 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
" so, please remove it. The fuzzer should be seeded with "
|
" so, please remove it. The fuzzer should be seeded with "
|
||||||
"interesting\n"
|
"interesting\n"
|
||||||
" inputs - but not ones that cause an outright crash.\n\n"
|
" inputs - but not ones that cause an outright crash.\n\n"
|
||||||
|
"%s"
|
||||||
|
|
||||||
" - The current memory limit (%s) is too low for this "
|
" - The current memory limit (%s) is too low for this "
|
||||||
"program, causing\n"
|
"program, causing\n"
|
||||||
@ -1085,6 +1127,7 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
"other options\n"
|
"other options\n"
|
||||||
" fail, poke the Awesome Fuzzing Discord for "
|
" fail, poke the Awesome Fuzzing Discord for "
|
||||||
"troubleshooting tips.\n",
|
"troubleshooting tips.\n",
|
||||||
|
msg_exit_code,
|
||||||
stringify_mem_size(val_buf, sizeof(val_buf),
|
stringify_mem_size(val_buf, sizeof(val_buf),
|
||||||
afl->fsrv.mem_limit << 20),
|
afl->fsrv.mem_limit << 20),
|
||||||
afl->fsrv.mem_limit - 1);
|
afl->fsrv.mem_limit - 1);
|
||||||
@ -1101,6 +1144,7 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
" so, please remove it. The fuzzer should be seeded with "
|
" so, please remove it. The fuzzer should be seeded with "
|
||||||
"interesting\n"
|
"interesting\n"
|
||||||
" inputs - but not ones that cause an outright crash.\n\n"
|
" inputs - but not ones that cause an outright crash.\n\n"
|
||||||
|
"%s"
|
||||||
|
|
||||||
" - In QEMU persistent mode the selected address(es) for the "
|
" - In QEMU persistent mode the selected address(es) for the "
|
||||||
"loop are not\n"
|
"loop are not\n"
|
||||||
@ -1113,7 +1157,8 @@ void perform_dry_run(afl_state_t *afl) {
|
|||||||
" - Least likely, there is a horrible bug in the fuzzer. If "
|
" - Least likely, there is a horrible bug in the fuzzer. If "
|
||||||
"other options\n"
|
"other options\n"
|
||||||
" fail, poke the Awesome Fuzzing Discord for "
|
" fail, poke the Awesome Fuzzing Discord for "
|
||||||
"troubleshooting tips.\n");
|
"troubleshooting tips.\n",
|
||||||
|
msg_exit_code);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3118,11 +3163,23 @@ void check_binary(afl_state_t *afl, u8 *fname) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (afl_memmem(f_data, f_len, "__asan_init", 11) ||
|
afl->fsrv.uses_asan = 0;
|
||||||
afl_memmem(f_data, f_len, "__msan_init", 11) ||
|
|
||||||
afl_memmem(f_data, f_len, "__lsan_init", 11)) {
|
|
||||||
|
|
||||||
afl->fsrv.uses_asan = 1;
|
if (afl_memmem(f_data, f_len, "__asan_init", 11)) {
|
||||||
|
|
||||||
|
afl->fsrv.uses_asan |= 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (afl_memmem(f_data, f_len, "__lsan_init", 11)) {
|
||||||
|
|
||||||
|
afl->fsrv.uses_asan |= 2;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (afl_memmem(f_data, f_len, "__msan_init", 11)) {
|
||||||
|
|
||||||
|
afl->fsrv.uses_asan |= 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user