about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJoshua Rogers <jrogers@opera.com>2021-04-02 22:23:11 +0000
committerJoshua Rogers <jrogers@opera.com>2021-04-02 22:23:11 +0000
commit920e9402a4d6101bbbed2ef7584d85a3c3de0eaa (patch)
treec8d8a258835b09099a30d9302ef0a9114a3ecae2 /src
parente98cd008222aa3bfea9b696ad756163302437eb3 (diff)
downloadafl++-920e9402a4d6101bbbed2ef7584d85a3c3de0eaa.tar.gz
Add support for standalone leak-sanitizer, introducting the environment
variable AFL_USE_LSAN.

AFL_USE_LSAN introduces the macro __AFL_CHECK_LEAK() which will check
for a memory leak when the macro is run. This is especially helpful
when using __AFL_LOOP().

If __AFL_LEAK_CHECK() is not used when AFL_USE_LSAN=1 is set,
the leak checker will run when the program exits.
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c19
-rw-r--r--src/afl-as.c7
-rw-r--r--src/afl-cc.c16
-rw-r--r--src/afl-forkserver.c17
-rw-r--r--src/afl-fuzz-init.c17
-rw-r--r--src/afl-showmap.c4
-rw-r--r--src/afl-tmin.c18
7 files changed, 88 insertions, 10 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 86b0f7e9..90305714 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -781,6 +781,19 @@ static void set_up_environment(void) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) {
+
+      FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY(
+          LSAN_ERROR) " - please fix!");
+
+    }
+
+  }
+
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -818,6 +831,12 @@ static void set_up_environment(void) {
                          "handle_sigfpe=0:"
                          "handle_sigill=0", 0);
 
+   setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(MSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0",
+         0);
+
+
   if (get_afl_env("AFL_PRELOAD")) {
 
     if (qemu_mode) {
diff --git a/src/afl-as.c b/src/afl-as.c
index 7de267a3..dfae44f2 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 5251465b..e0478503 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -758,7 +758,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list="))
       have_instr_list = 1;
 
-    if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
+    if (!(strcmp(cur, "-fsanitize=address") && strcmp(cur, "-fsanitize=memory")))
       asan_set = 1;
 
     if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
@@ -817,6 +817,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
+  if (getenv("AFL_USE_LSAN")) {
+    cc_params[cc_par_cnt++] = "-fsanitize=leak";
+  }
+
   if (getenv("AFL_USE_CFISAN")) {
 
     if (!lto_mode) {
@@ -914,6 +918,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
   }
 
+  if (getenv("AFL_USE_LSAN")) {
+    cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h";
+  }
+
+  cc_params[cc_par_cnt++] =
+      "-D__AFL_CHECK_LEAK()=__lsan_do_leak_check()";
+
   cc_params[cc_par_cnt++] =
       "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
       "1;";
@@ -1740,7 +1751,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 68995388..fa89713a 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -483,7 +483,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",
@@ -500,7 +500,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",
@@ -538,6 +538,14 @@ 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",
+            1);
+
     fsrv->init_child_func(fsrv, argv);
 
     /* Use a distinctive bitmap signature to tell the parent about execv()
@@ -1210,8 +1218,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 82c1799e..24f5c5b5 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -2466,6 +2466,20 @@ void check_asan_opts(afl_state_t *afl) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) {
+
+      FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY(
+          LSAN_ERROR) " - please fix!");
+
+    }
+
+  }
+
+
 }
 
 /* Handle stop signal (Ctrl-C, etc). */
@@ -2711,7 +2725,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 7bf5a9c7..bf076683 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -570,6 +570,10 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
          "handle_sigfpe=0:"
          "handle_sigill=0",
          0);
+  setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0",
+          0);
 
   setenv("UBSAN_OPTIONS",
          "halt_on_error=1:"
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index 7ef8b9bf..a2741a07 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -712,6 +712,19 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
 
   }
 
+  x = get_afl_env("LSAN_OPTIONS");
+
+  if (x) {
+
+    if (!strstr(x, "exit_code=" STRINGIFY(LSAN_ERROR))) {
+
+      FATAL("Custom LSAN_OPTIONS set without exit_code=" STRINGIFY(
+          LSAN_ERROR) " - please fix!");
+
+    }
+
+  }
+
   setenv("ASAN_OPTIONS",
          "abort_on_error=1:"
          "detect_leaks=0:"
@@ -749,6 +762,11 @@ static void set_up_environment(afl_forkserver_t *fsrv) {
                          "handle_sigfpe=0:"
                          "handle_sigill=0", 0);
 
+   setenv("LSAN_OPTIONS",
+         "exitcode=" STRINGIFY(LSAN_ERROR) ":"
+         "fast_unwind_on_malloc=0",
+         0);
+
   if (get_afl_env("AFL_PRELOAD")) {
 
     if (fsrv->qemu_mode) {