Merge pull request #855 from MegaManSec/leak-sanitizer

Add support for standalone leak-sanitizer
This commit is contained in:
van Hauser
2021-04-04 15:28:42 +02:00
committed by GitHub
14 changed files with 123 additions and 16 deletions

View File

@ -517,7 +517,7 @@ code-format:
ifndef AFL_NO_X86 ifndef AFL_NO_X86
test_build: afl-cc afl-gcc afl-as afl-showmap test_build: afl-cc afl-gcc afl-as afl-showmap
@echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..." @echo "[*] Testing the CC wrapper afl-cc and its instrumentation output..."
@unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 ) @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-cc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-cc failed"; exit 1 )
ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
@rm -f test-instr @rm -f test-instr
@ -525,7 +525,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap
@echo @echo
@echo "[+] All right, the instrumentation of afl-cc seems to be working!" @echo "[+] All right, the instrumentation of afl-cc seems to be working!"
# @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..." # @echo "[*] Testing the CC wrapper afl-gcc and its instrumentation output..."
# @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 ) # @unset AFL_MAP_SIZE AFL_USE_UBSAN AFL_USE_CFISAN AFL_USE_LSAN AFL_USE_ASAN AFL_USE_MSAN; AFL_CC=$(CC) ASAN_OPTIONS=detect_leaks=0 AFL_INST_RATIO=100 AFL_PATH=. ./afl-gcc test-instr.c -o test-instr 2>&1 || (echo "Oops, afl-gcc failed"; exit 1 )
# ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null # ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr0 ./test-instr < /dev/null
# echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr # echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
# @rm -f test-instr # @rm -f test-instr

View File

@ -605,7 +605,7 @@ Every -M/-S entry needs a unique name (that can be whatever), however the same
For every secondary fuzzer there should be a variation, e.g.: For every secondary fuzzer there should be a variation, e.g.:
* one should fuzz the target that was compiled differently: with sanitizers * one should fuzz the target that was compiled differently: with sanitizers
activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ; activated (`export AFL_USE_ASAN=1 ; export AFL_USE_UBSAN=1 ;
export AFL_USE_CFISAN=1 ; ` export AFL_USE_CFISAN=1 ; export AFL_USE_LSAN=1`)
* one should fuzz the target with CMPLOG/redqueen (see above) * one should fuzz the target with CMPLOG/redqueen (see above)
* one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV * one to three fuzzers should fuzz a target compiled with laf-intel/COMPCOV
(see above). Important note: If you run more than one laf-intel/COMPCOV (see above). Important note: If you run more than one laf-intel/COMPCOV

View File

@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead:
overridden. overridden.
- Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your - Setting `AFL_USE_ASAN` automatically enables ASAN, provided that your
compiler supports that. Note that fuzzing with ASAN is mildly challenging compiler supports it. Note that fuzzing with ASAN is mildly challenging
- see [notes_for_asan.md](notes_for_asan.md). - see [notes_for_asan.md](notes_for_asan.md).
(You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the (You can also enable MSAN via `AFL_USE_MSAN`; ASAN and MSAN come with the
@ -64,6 +64,13 @@ make fairly broad use of environmental variables instead:
there is the Control Flow Integrity sanitizer that can be activated by there is the Control Flow Integrity sanitizer that can be activated by
`AFL_USE_CFISAN=1`) `AFL_USE_CFISAN=1`)
- Setting `AFL_USE_LSAN` automatically enables Leak-Sanitizer, provided
that your compiler supports it. To perform a leak check within your
program at a certain point (such as at the end of an __AFL_LOOP),
you can run the macro __AFL_LEAK_CHECK(); which will cause
an abort if any memory is leaked (you can combine this with the
LSAN_OPTIONS=suppressions option to supress some known leaks).
- Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream - Setting `AFL_CC`, `AFL_CXX`, and `AFL_AS` lets you use alternate downstream
compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
in your `$PATH`. in your `$PATH`.
@ -627,7 +634,14 @@ optimal values if not already present in the environment:
msan_track_origins=0 msan_track_origins=0
allocator_may_return_null=1 allocator_may_return_null=1
``` ```
Be sure to include the first one when customizing anything, since some - Similarly, the default `LSAN_OPTIONS` are set to:
MSAN versions don't call `abort()` on error, and we need a way to detect ```
faults. exit_code=23
fast_unwind_on_malloc=0
symbolize=0
print_suppressions=0
```
Be sure to include the first ones for LSAN and MSAN when customizing
anything, since some MSAN and LSAN versions don't call `abort()` on
error, and we need a way to detect faults.

View File

@ -28,6 +28,13 @@ Note that ASAN is incompatible with -static, so be mindful of that.
(You can also use AFL_USE_MSAN=1 to enable MSAN instead.) (You can also use AFL_USE_MSAN=1 to enable MSAN instead.)
When compiling with AFL_USE_LSAN, the leak sanitizer will normally run
when the program exits. In order to utilize this check at different times,
such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();.
This macro will report a crash in afl-fuzz if any memory is left leaking
at this stage. You can also use LSAN_OPTIONS and a supressions file
for more fine-tuned checking, however make sure you keep exitcode=23.
NOTE: if you run several secondary instances, only one should run the target NOTE: if you run several secondary instances, only one should run the target
compiled with ASAN (and UBSAN, CFISAN), the others should run the target with compiled with ASAN (and UBSAN, CFISAN), the others should run the target with
no sanitizers compiled in. no sanitizers compiled in.

View File

@ -406,6 +406,10 @@
#define MSAN_ERROR 86 #define MSAN_ERROR 86
/* Distinctive exit code used to indicate LSAN trip condition: */
#define LSAN_ERROR 23
/* Designated file descriptors for forkserver commands (the application will /* Designated file descriptors for forkserver commands (the application will
use FORKSRV_FD and FORKSRV_FD + 1): */ use FORKSRV_FD and FORKSRV_FD + 1): */

View File

@ -181,6 +181,7 @@ static char *afl_environment_variables[] = {
"AFL_USE_TRACE_PC", "AFL_USE_TRACE_PC",
"AFL_USE_UBSAN", "AFL_USE_UBSAN",
"AFL_USE_CFISAN", "AFL_USE_CFISAN",
"AFL_USE_LSAN",
"AFL_WINE_PATH", "AFL_WINE_PATH",
"AFL_NO_SNAPSHOT", "AFL_NO_SNAPSHOT",
"AFL_EXPAND_HAVOC_NOW", "AFL_EXPAND_HAVOC_NOW",

View File

@ -784,6 +784,18 @@ static void set_up_environment(char **argv) {
} }
x = get_afl_env("LSAN_OPTIONS");
if (x) {
if (!strstr(x, "symbolize=0")) {
FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
}
}
setenv("ASAN_OPTIONS", setenv("ASAN_OPTIONS",
"abort_on_error=1:" "abort_on_error=1:"
"detect_leaks=0:" "detect_leaks=0:"
@ -821,6 +833,14 @@ static void set_up_environment(char **argv) {
"handle_sigfpe=0:" "handle_sigfpe=0:"
"handle_sigill=0", 0); "handle_sigill=0", 0);
setenv("LSAN_OPTIONS",
"exitcode=" STRINGIFY(LSAN_ERROR) ":"
"fast_unwind_on_malloc=0:"
"symbolize=0:"
"print_suppressions=0",
0);
if (get_afl_env("AFL_PRELOAD")) { if (get_afl_env("AFL_PRELOAD")) {
if (qemu_mode) { if (qemu_mode) {

View File

@ -517,11 +517,12 @@ static void add_instrumentation(void) {
} else { } else {
char modeline[100]; char modeline[100];
snprintf(modeline, sizeof(modeline), "%s%s%s%s", snprintf(modeline, sizeof(modeline), "%s%s%s%s%s",
getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
getenv("AFL_USE_ASAN") ? ", ASAN" : "", getenv("AFL_USE_ASAN") ? ", ASAN" : "",
getenv("AFL_USE_MSAN") ? ", MSAN" : "", getenv("AFL_USE_MSAN") ? ", MSAN" : "",
getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); getenv("AFL_USE_UBSAN") ? ", UBSAN" : "",
getenv("AFL_USE_LSAN") ? ", LSAN" : "");
OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines, OKF("Instrumented %u locations (%s-bit, %s mode, ratio %u%%).", ins_lines,
use_64bit ? "64" : "32", modeline, inst_ratio); use_64bit ? "64" : "32", modeline, inst_ratio);
@ -585,7 +586,7 @@ int main(int argc, char **argv) {
"AFL_QUIET: suppress verbose output\n" "AFL_QUIET: suppress verbose output\n"
"AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n" "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\n"
"AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n" "AFL_AS_FORCE_INSTRUMENT: force instrumentation for asm sources\n"
"AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN:\n" "AFL_HARDEN, AFL_USE_ASAN, AFL_USE_MSAN, AFL_USE_UBSAN, AFL_USE_LSAN:\n"
" used in the instrumentation summary message\n", " used in the instrumentation summary message\n",
argv[0]); argv[0]);

View File

@ -819,6 +819,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
} }
if (getenv("AFL_USE_LSAN")) {
cc_params[cc_par_cnt++] = "-fsanitize=leak";
cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h";
cc_params[cc_par_cnt++] =
"-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()";
}
if (getenv("AFL_USE_CFISAN")) { if (getenv("AFL_USE_CFISAN")) {
if (!lto_mode) { if (!lto_mode) {
@ -1730,7 +1737,8 @@ int main(int argc, char **argv, char **envp) {
" AFL_USE_ASAN: activate address sanitizer\n" " AFL_USE_ASAN: activate address sanitizer\n"
" AFL_USE_CFISAN: activate control flow sanitizer\n" " AFL_USE_CFISAN: activate control flow sanitizer\n"
" AFL_USE_MSAN: activate memory sanitizer\n" " AFL_USE_MSAN: activate memory sanitizer\n"
" AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"); " AFL_USE_UBSAN: activate undefined behaviour sanitizer\n"
" AFL_USE_LSAN: activate leak-checker sanitizer\n");
if (have_gcc_plugin) if (have_gcc_plugin)
SAYF( SAYF(

View File

@ -502,7 +502,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); } if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
/* Set sane defaults for ASAN if nothing else specified. */ /* Set sane defaults for ASAN if nothing else is specified. */
if (!getenv("ASAN_OPTIONS")) if (!getenv("ASAN_OPTIONS"))
setenv("ASAN_OPTIONS", setenv("ASAN_OPTIONS",
@ -519,7 +519,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"handle_sigill=0", "handle_sigill=0",
1); 1);
/* Set sane defaults for UBSAN if nothing else specified. */ /* Set sane defaults for UBSAN if nothing else is specified. */
if (!getenv("UBSAN_OPTIONS")) if (!getenv("UBSAN_OPTIONS"))
setenv("UBSAN_OPTIONS", setenv("UBSAN_OPTIONS",
@ -557,6 +557,16 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
"handle_sigill=0", "handle_sigill=0",
1); 1);
/* LSAN, too, does not support abort_on_error=1. */
if (!getenv("LSAN_OPTIONS"))
setenv("LSAN_OPTIONS",
"exitcode=" STRINGIFY(LSAN_ERROR) ":"
"fast_unwind_on_malloc=0:"
"symbolize=0:"
"print_suppressions=0",
1);
fsrv->init_child_func(fsrv, argv); fsrv->init_child_func(fsrv, argv);
/* Use a distinctive bitmap signature to tell the parent about execv() /* Use a distinctive bitmap signature to tell the parent about execv()
@ -1303,8 +1313,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (unlikely( if (unlikely(
/* A normal crash/abort */ /* A normal crash/abort */
(WIFSIGNALED(fsrv->child_status)) || (WIFSIGNALED(fsrv->child_status)) ||
/* special handling for msan */ /* special handling for msan and lsan */
(fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) || (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
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))) {

View File

@ -2490,6 +2490,19 @@ void check_asan_opts(afl_state_t *afl) {
} }
x = get_afl_env("LSAN_OPTIONS");
if (x) {
if (!strstr(x, "symbolize=0")) {
FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
}
}
} }
/* Handle stop signal (Ctrl-C, etc). */ /* Handle stop signal (Ctrl-C, etc). */
@ -2735,7 +2748,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
} }
if (memmem(f_data, f_len, "__asan_init", 11) || if (memmem(f_data, f_len, "__asan_init", 11) ||
memmem(f_data, f_len, "__msan_init", 11)) { memmem(f_data, f_len, "__msan_init", 11) ||
memmem(f_data, f_len, "__lsan_init", 11)) {
afl->fsrv.uses_asan = 1; afl->fsrv.uses_asan = 1;

View File

@ -572,6 +572,13 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
"handle_sigill=0", "handle_sigill=0",
0); 0);
setenv("LSAN_OPTIONS",
"exitcode=" STRINGIFY(LSAN_ERROR) ":"
"fast_unwind_on_malloc=0:"
"symbolize=0:"
"print_suppressions=0",
0);
setenv("UBSAN_OPTIONS", setenv("UBSAN_OPTIONS",
"halt_on_error=1:" "halt_on_error=1:"
"abort_on_error=1:" "abort_on_error=1:"

View File

@ -714,6 +714,18 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
} }
x = get_afl_env("LSAN_OPTIONS");
if (x) {
if (!strstr(x, "symbolize=0")) {
FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
}
}
setenv("ASAN_OPTIONS", setenv("ASAN_OPTIONS",
"abort_on_error=1:" "abort_on_error=1:"
"detect_leaks=0:" "detect_leaks=0:"
@ -751,6 +763,13 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
"handle_sigfpe=0:" "handle_sigfpe=0:"
"handle_sigill=0", 0); "handle_sigill=0", 0);
setenv("LSAN_OPTIONS",
"exitcode=" STRINGIFY(LSAN_ERROR) ":"
"fast_unwind_on_malloc=0:"
"symbolize=0:"
"print_suppressions=0",
0);
if (get_afl_env("AFL_PRELOAD")) { if (get_afl_env("AFL_PRELOAD")) {
if (fsrv->qemu_mode) { if (fsrv->qemu_mode) {

View File

@ -71,6 +71,7 @@ unset AFL_HARDEN
unset AFL_USE_ASAN unset AFL_USE_ASAN
unset AFL_USE_MSAN unset AFL_USE_MSAN
unset AFL_USE_UBSAN unset AFL_USE_UBSAN
unset AFL_USE_LSAN
unset AFL_TMPDIR unset AFL_TMPDIR
unset AFL_CC unset AFL_CC
unset AFL_PRELOAD unset AFL_PRELOAD