about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-04-04 15:28:42 +0200
committerGitHub <noreply@github.com>2021-04-04 15:28:42 +0200
commitc23183f1dc39ce0792a879065e6aea33a4c571f8 (patch)
tree68acaf32c888de02334d15814743c1463c564c15
parent53facd8882173873a7b78860b0fb49884de90c5b (diff)
parent99819cf5d1cbc262810f26098a5796c9d1262bc5 (diff)
downloadafl++-c23183f1dc39ce0792a879065e6aea33a4c571f8.tar.gz
Merge pull request #855 from MegaManSec/leak-sanitizer
 Add support for standalone leak-sanitizer
-rw-r--r--GNUmakefile4
-rw-r--r--README.md2
-rw-r--r--docs/env_variables.md22
-rw-r--r--docs/notes_for_asan.md7
-rw-r--r--include/config.h4
-rw-r--r--include/envs.h1
-rw-r--r--src/afl-analyze.c20
-rw-r--r--src/afl-as.c7
-rw-r--r--src/afl-cc.c10
-rw-r--r--src/afl-forkserver.c19
-rw-r--r--src/afl-fuzz-init.c16
-rw-r--r--src/afl-showmap.c7
-rw-r--r--src/afl-tmin.c19
-rwxr-xr-xtest/test-pre.sh1
14 files changed, 123 insertions, 16 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 963004bd..fdbcd542 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -517,7 +517,7 @@ code-format:
 ifndef AFL_NO_X86
 test_build: afl-cc afl-gcc afl-as afl-showmap
 	@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
 	echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
 	@rm -f test-instr
@@ -525,7 +525,7 @@ test_build: afl-cc afl-gcc afl-as afl-showmap
 	@echo
 	@echo "[+] All right, the instrumentation of afl-cc seems to be working!"
 #	@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
 #	echo 1 | ASAN_OPTIONS=detect_leaks=0 ./afl-showmap -m none -q -o .test-instr1 ./test-instr
 #	@rm -f test-instr
diff --git a/README.md b/README.md
index b0ed8634..c94872be 100644
--- a/README.md
+++ b/README.md
@@ -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.:
  * one should fuzz the target that was compiled differently: with sanitizers
    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 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
diff --git a/docs/env_variables.md b/docs/env_variables.md
index 899b36cc..8d482e20 100644
--- a/docs/env_variables.md
+++ b/docs/env_variables.md
@@ -55,7 +55,7 @@ make fairly broad use of environmental variables instead:
     overridden.
 
   - 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).
 
     (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
     `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
     compilation tools, rather than the default 'clang', 'gcc', or 'as' binaries
     in your `$PATH`.
@@ -627,7 +634,14 @@ optimal values if not already present in the environment:
     msan_track_origins=0
     allocator_may_return_null=1
 ```
-  Be sure to include the first one when customizing anything, since some
-    MSAN versions don't call `abort()` on error, and we need a way to detect
-    faults.
+  - Similarly, the default `LSAN_OPTIONS` are set to:
+```
+    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.
 
diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md
index 2b3bc028..f55aeaf2 100644
--- a/docs/notes_for_asan.md
+++ b/docs/notes_for_asan.md
@@ -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.)
 
+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
 compiled with ASAN (and UBSAN, CFISAN), the others should run the target with
 no sanitizers compiled in.
diff --git a/include/config.h b/include/config.h
index 75f363f7..aa24ea6c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -406,6 +406,10 @@
 
 #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
    use FORKSRV_FD and FORKSRV_FD + 1): */
 
diff --git a/include/envs.h b/include/envs.h
index f7c8b460..887e2c4f 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -181,6 +181,7 @@ static char *afl_environment_variables[] = {
     "AFL_USE_TRACE_PC",
     "AFL_USE_UBSAN",
     "AFL_USE_CFISAN",
+    "AFL_USE_LSAN",
     "AFL_WINE_PATH",
     "AFL_NO_SNAPSHOT",
     "AFL_EXPAND_HAVOC_NOW",
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 8e5a1772..7d7519fa 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -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",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -821,6 +833,14 @@ static void set_up_environment(char **argv) {
                          "handle_sigfpe=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 (qemu_mode) {
diff --git a/src/afl-as.c b/src/afl-as.c
index aebd0ac8..7119d630 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -517,11 +517,12 @@ static void add_instrumentation(void) {
     } else {
 
       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_USE_ASAN") ? ", ASAN" : "",
                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,
           use_64bit ? "64" : "32", modeline, inst_ratio);
@@ -585,7 +586,7 @@ int main(int argc, char **argv) {
         "AFL_QUIET: suppress verbose output\n"
         "AFL_KEEP_ASSEMBLY: leave instrumented assembly files\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",
         argv[0]);
 
diff --git a/src/afl-cc.c b/src/afl-cc.c
index b354077e..d4c0a6b7 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -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 (!lto_mode) {
@@ -1730,7 +1737,8 @@ int main(int argc, char **argv, char **envp) {
           "  AFL_USE_ASAN: activate address sanitizer\n"
           "  AFL_USE_CFISAN: activate control flow 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)
         SAYF(
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 0037d2d5..cd04e23d 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -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); }
 
-    /* Set sane defaults for ASAN if nothing else specified. */
+    /* Set sane defaults for ASAN if nothing else is specified. */
 
     if (!getenv("ASAN_OPTIONS"))
       setenv("ASAN_OPTIONS",
@@ -519,7 +519,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
              "handle_sigill=0",
              1);
 
-    /* Set sane defaults for UBSAN if nothing else specified. */
+    /* Set sane defaults for UBSAN if nothing else is specified. */
 
     if (!getenv("UBSAN_OPTIONS"))
       setenv("UBSAN_OPTIONS",
@@ -557,6 +557,16 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
            "handle_sigill=0",
            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);
 
     /* 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(
           /* A normal crash/abort */
           (WIFSIGNALED(fsrv->child_status)) ||
-          /* special handling for msan */
-          (fsrv->uses_asan && WEXITSTATUS(fsrv->child_status) == MSAN_ERROR) ||
+          /* special handling for msan and lsan */
+          (fsrv->uses_asan && (WEXITSTATUS(fsrv->child_status) == MSAN_ERROR ||
+          WEXITSTATUS(fsrv->child_status) == LSAN_ERROR)) ||
           /* the custom crash_exitcode was returned by the target */
           (fsrv->uses_crash_exitcode &&
            WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index cb0190a0..48f3289d 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -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). */
@@ -2735,7 +2748,8 @@ void check_binary(afl_state_t *afl, u8 *fname) {
   }
 
   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;
 
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 38d03d80..946b19cd 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -572,6 +572,13 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
          "handle_sigill=0",
          0);
 
+  setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0:"
+         "symbolize=0:"
+         "print_suppressions=0",
+          0);
+
   setenv("UBSAN_OPTIONS",
          "halt_on_error=1:"
          "abort_on_error=1:"
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index bad5d71b..6aad748c 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -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",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -751,6 +763,13 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
                          "handle_sigfpe=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 (fsrv->qemu_mode) {
diff --git a/test/test-pre.sh b/test/test-pre.sh
index 85ac320b..174f2f7f 100755
--- a/test/test-pre.sh
+++ b/test/test-pre.sh
@@ -71,6 +71,7 @@ unset AFL_HARDEN
 unset AFL_USE_ASAN
 unset AFL_USE_MSAN
 unset AFL_USE_UBSAN
+unset AFL_USE_LSAN
 unset AFL_TMPDIR
 unset AFL_CC
 unset AFL_PRELOAD