about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--docs/Changelog.md2
-rw-r--r--examples/persistent_demo/persistent_demo.c14
-rw-r--r--examples/persistent_demo/persistent_demo_new.c118
-rw-r--r--include/afl-fuzz.h1
-rw-r--r--include/config.h4
-rw-r--r--include/forkserver.h8
-rw-r--r--include/types.h3
-rw-r--r--llvm_mode/afl-clang-fast.c8
-rw-r--r--llvm_mode/afl-llvm-rt.o.c91
-rw-r--r--src/afl-forkserver.c79
-rw-r--r--src/afl-fuzz-init.c24
-rw-r--r--src/afl-fuzz-run.c10
-rw-r--r--src/afl-fuzz.c8
13 files changed, 340 insertions, 30 deletions
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 6115a0cc..884de0b1 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -10,6 +10,8 @@ sending a mail to <afl-users+subscribe@googlegroups.com>.
 
 
 ### Version ++2.65d (dev)
+  - initial support for persistent mode shared memory testcase handover
+    (instead of via files/stdin)
   - afl-fuzz:
      - -S slaves now only sync from the master to increase performance,
        the -M master stilly syncs from everyone. Added checks that exactly
diff --git a/examples/persistent_demo/persistent_demo.c b/examples/persistent_demo/persistent_demo.c
index 36f12850..41cd9e38 100644
--- a/examples/persistent_demo/persistent_demo.c
+++ b/examples/persistent_demo/persistent_demo.c
@@ -63,7 +63,7 @@ int main(int argc, char **argv) {
                We just have some trivial inline code that faults on 'foo!'. */
 
     /* do we have enough data? */
-    if (len < 4) return 0;
+    if (len < 8) return 0;
 
     if (buf[0] == 'f') {
 
@@ -77,7 +77,17 @@ int main(int argc, char **argv) {
           if (buf[3] == '!') {
 
             printf("four\n");
-            abort();
+            if (buf[4] == '!') {
+
+              printf("five\n");
+              if (buf[5] == '!') {
+
+                printf("six\n");
+                abort();
+
+              }
+
+            }
 
           }
 
diff --git a/examples/persistent_demo/persistent_demo_new.c b/examples/persistent_demo/persistent_demo_new.c
new file mode 100644
index 00000000..fffd40b6
--- /dev/null
+++ b/examples/persistent_demo/persistent_demo_new.c
@@ -0,0 +1,118 @@
+/*
+   american fuzzy lop++ - persistent mode example
+   --------------------------------------------
+
+   Originally written by Michal Zalewski
+
+   Copyright 2015 Google Inc. All rights reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at:
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+   This file demonstrates the high-performance "persistent mode" that may be
+   suitable for fuzzing certain fast and well-behaved libraries, provided that
+   they are stateless or that their internal state can be easily reset
+   across runs.
+
+   To make this work, the library and this shim need to be compiled in LLVM
+   mode using afl-clang-fast (other compiler wrappers will *not* work).
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+__AFL_FUZZ_INIT();
+
+unsigned int crc32_for_byte(unsigned int r) {
+
+  for (int j = 0; j < 8; ++j)
+    r = (r & 1 ? 0 : (unsigned int)0xEDB88320L) ^ r >> 1;
+  return r ^ (unsigned int)0xFF000000L;
+
+}
+
+unsigned int crc32(unsigned char *data, unsigned int n_bytes) {
+
+  static unsigned char table[0x100];
+  unsigned int         crc = 0;
+  if (!*table)
+    for (unsigned int i = 0; i < 0x100; ++i)
+      table[i] = crc32_for_byte(i);
+  for (unsigned int i = 0; i < n_bytes; ++i)
+    crc = table[(unsigned char)crc ^ (data)[i]] ^ crc >> 8;
+  return crc;
+
+}
+
+/* Main entry point. */
+
+int main(int argc, char **argv) {
+
+  ssize_t        len;                        /* how much input did we read? */
+  unsigned char *buf;                        /* test case buffer pointer    */
+
+  /* The number passed to __AFL_LOOP() controls the maximum number of
+     iterations before the loop exits and the program is allowed to
+     terminate normally. This limits the impact of accidental memory leaks
+     and similar hiccups. */
+
+  buf = __AFL_FUZZ_TESTCASE_BUF;
+
+  while (__AFL_LOOP(1000)) {
+
+    len = __AFL_FUZZ_TESTCASE_LEN;
+
+    /* do we have enough data? */
+    if (len < 8) return 0;
+
+    if (buf[0] == 'f') {
+
+      printf("one\n");
+      if (buf[1] == 'o') {
+
+        printf("two\n");
+        if (buf[2] == 'o') {
+
+          printf("three\n");
+          if (buf[3] == '!') {
+
+            printf("four\n");
+            if (buf[4] == '!') {
+
+              printf("five\n");
+              if (buf[6] == '!') {
+
+                printf("six\n");
+                abort();
+
+              }
+
+            }
+
+          }
+
+        }
+
+      }
+
+    }
+
+    /*** END PLACEHOLDER CODE ***/
+
+  }
+
+  /* Once the loop is exited, terminate normally - AFL will restart the process
+     when this happens, with a clean slate when it comes to allocated memory,
+     leftover file descriptors, etc. */
+
+  return 0;
+
+}
+
diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h
index 6e74f824..32ae2a58 100644
--- a/include/afl-fuzz.h
+++ b/include/afl-fuzz.h
@@ -342,6 +342,7 @@ typedef struct afl_state {
 
   afl_forkserver_t fsrv;
   sharedmem_t      shm;
+  sharedmem_t *    shm_fuzz;
   afl_env_vars_t   afl_env;
 
   char **argv;                                            /* argv if needed */
diff --git a/include/config.h b/include/config.h
index 6fde8b36..57efd0f6 100644
--- a/include/config.h
+++ b/include/config.h
@@ -304,6 +304,10 @@
 
 #define SHM_ENV_VAR "__AFL_SHM_ID"
 
+/* Environment variable used to pass SHM FUZZ ID to the called program. */
+
+#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
+
 /* Other less interesting, internal-only variables. */
 
 #define CLANG_ENV_VAR "__AFL_CLANG_MODE"
diff --git a/include/forkserver.h b/include/forkserver.h
index e8ac2837..00555d7e 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -73,10 +73,18 @@ typedef struct afl_forkserver {
 
   u8 last_kill_signal;                  /* Signal that killed the child     */
 
+  u8 use_shdmen_fuzz;                   /* use shared mem for test cases    */
+
+  u8 support_shdmen_fuzz;               /* set by afl-fuzz                  */
+
   u8 use_fauxsrv;                       /* Fauxsrv for non-forking targets? */
 
   u8 qemu_mode;                         /* if running in qemu mode or not   */
 
+  u32 shdmem_fuzz_len;                   /* length of the fuzzing test case */
+
+  u8 *shdmem_fuzz;                      /* allocated memory for fuzzing     */
+
   char *cmplog_binary;                  /* the name of the cmplog binary    */
 
   /* Function to kick off the forkserver child */
diff --git a/include/types.h b/include/types.h
index f95c4be2..95ca2689 100644
--- a/include/types.h
+++ b/include/types.h
@@ -43,10 +43,11 @@ typedef uint32_t u32;
 #define FS_ERROR_MMAP 16
 
 /* Reporting options */
-#define FS_OPT_ENABLED 0x8f000001
+#define FS_OPT_ENABLED 0x80000001
 #define FS_OPT_MAPSIZE 0x40000000
 #define FS_OPT_SNAPSHOT 0x20000000
 #define FS_OPT_AUTODICT 0x10000000
+#define FS_OPT_SHDMEM_FUZZ 0x01000000
 // FS_OPT_MAX_MAPSIZE is 8388608 = 0x800000 = 2^23 = 1 << 22
 #define FS_OPT_MAX_MAPSIZE ((0x00fffffe >> 1) + 1)
 #define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1)
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 8791c5ae..e8f20bb2 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -490,6 +490,14 @@ static void edit_params(u32 argc, char **argv, char **envp) {
    */
 
   cc_params[cc_par_cnt++] =
+      "-D__AFL_FUZZ_INIT()="
+      "int __afl_sharedmem_fuzzing = 1;"
+      "extern unsigned int __afl_fuzz_len;"
+      "extern unsigned char *__afl_fuzz_ptr;";
+  cc_params[cc_par_cnt++] = "-D__AFL_FUZZ_TESTCASE_BUF=__afl_fuzz_ptr";
+  cc_params[cc_par_cnt++] = "-D__AFL_FUZZ_TESTCASE_LEN=__afl_fuzz_len";
+
+  cc_params[cc_par_cnt++] =
       "-D__AFL_LOOP(_A)="
       "({ static volatile char *_B __attribute__((used)); "
       " _B = (char*)\"" PERSIST_SIG
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index dac35796..a461bc03 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -76,6 +76,8 @@ u8                  __afl_area_initial[MAP_SIZE];
 #endif
 u8 *__afl_area_ptr = __afl_area_initial;
 u8 *__afl_dictionary;
+u8 *__afl_fuzz_ptr;
+u32 __afl_fuzz_len;
 
 u32 __afl_final_loc;
 u32 __afl_map_size = MAP_SIZE;
@@ -92,6 +94,8 @@ __thread u32        __afl_prev_ctx;
 __thread u32        __afl_cmp_counter;
 #endif
 
+int __afl_sharedmem_fuzzing __attribute__((weak));
+
 struct cmp_map *__afl_cmp_map;
 
 /* Running in persistent mode? */
@@ -109,6 +113,59 @@ void send_forkserver_error(int error) {
 
 }
 
+/* SHM fuzzing setup. */
+
+static void __afl_map_shm_fuzz() {
+
+  char *id_str = getenv(SHM_FUZZ_ENV_VAR);
+
+  if (id_str) {
+
+#ifdef USEMMAP
+    const char *   shm_file_path = id_str;
+    int            shm_fd = -1;
+    unsigned char *shm_base = NULL;
+
+    /* create the shared memory segment as if it was a file */
+    shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+    if (shm_fd == -1) {
+
+      fprintf(stderr, "shm_open() failed for fuzz\n");
+      send_forkserver_error(FS_ERROR_SHM_OPEN);
+      exit(1);
+
+    }
+
+    __afl_fuzz_ptr = mmap(0, MAX_FILE, PROT_READ, MAP_SHARED, shm_fd, 0);
+
+#else
+    u32 shm_id = atoi(id_str);
+
+    __afl_fuzz_ptr = shmat(shm_id, NULL, 0);
+
+#endif
+
+    /* Whooooops. */
+
+    if (__afl_fuzz_ptr == (void *)-1) {
+
+      fprintf(stderr, "Error: could not access fuzzing shared memory\n");
+      exit(1);
+
+    }
+
+    if (getenv("AFL_DEBUG"))
+      fprintf(stderr, "DEBUG: successfully got fuzzing shared memory\n");
+
+  } else {
+
+    fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
+    exit(1);
+
+  }
+
+}
+
 /* SHM setup. */
 
 static void __afl_map_shm(void) {
@@ -310,17 +367,25 @@ static void __afl_start_snapshots(void) {
      assume we're not running in forkserver mode and just execute program. */
 
   status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT);
+  if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
   if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
     status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
-  if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+  if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
   memcpy(tmp, &status, 4);
 
   if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
 
-  if (__afl_dictionary_len > 0 && __afl_dictionary) {
+  if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
 
     if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
 
+    if ((was_killed & (0xffffffff & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ))) ==
+        (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
+
+      __afl_map_shm_fuzz();
+
+    }
+
     if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
         (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
 
@@ -357,7 +422,7 @@ static void __afl_start_snapshots(void) {
 
       // uh this forkserver master does not understand extended option passing
       // or does not want the dictionary
-      already_read_first = 1;
+      if (!__afl_fuzz_ptr) already_read_first = 1;
 
     }
 
@@ -378,6 +443,9 @@ static void __afl_start_snapshots(void) {
 
     }
 
+    __afl_fuzz_len = (was_killed >> 8);
+    was_killed = (was_killed & 0xff);
+
     /* If we stopped the child in persistent mode, but there was a race
        condition and afl-fuzz already issued SIGKILL, write off the old
        process. */
@@ -473,7 +541,8 @@ static void __afl_start_forkserver(void) {
 
   if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
     status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
-  if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT;
+  if (__afl_dictionary_len && __afl_dictionary) status |= FS_OPT_AUTODICT;
+  if (__afl_sharedmem_fuzzing != 0) status |= FS_OPT_SHDMEM_FUZZ;
   if (status) status |= (FS_OPT_ENABLED);
   memcpy(tmp, &status, 4);
 
@@ -482,10 +551,17 @@ static void __afl_start_forkserver(void) {
 
   if (write(FORKSRV_FD + 1, tmp, 4) != 4) return;
 
-  if (__afl_dictionary_len > 0 && __afl_dictionary) {
+  if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
 
     if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
 
+    if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
+        (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
+
+      __afl_map_shm_fuzz();
+
+    }
+
     if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
         (FS_OPT_ENABLED | FS_OPT_AUTODICT)) {
 
@@ -522,7 +598,7 @@ static void __afl_start_forkserver(void) {
 
       // uh this forkserver master does not understand extended option passing
       // or does not want the dictionary
-      already_read_first = 1;
+      if (!__afl_fuzz_ptr) already_read_first = 1;
 
     }
 
@@ -544,6 +620,9 @@ static void __afl_start_forkserver(void) {
 
     }
 
+    __afl_fuzz_len = (was_killed >> 8);
+    was_killed = (was_killed & 0xff);
+
     /* If we stopped the child in persistent mode, but there was a race
        condition and afl-fuzz already issued SIGKILL, write off the old
        process. */
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index b67aedde..137a4f99 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -442,7 +442,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
 
-      if (!be_quiet && getenv("AFL_DEBUG")) {
+      if (getenv("AFL_DEBUG")) {
 
         ACTF("Extended forkserver functions received (%08x).", status);
 
@@ -455,6 +455,28 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
       }
 
+      if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
+
+        if (fsrv->support_shdmen_fuzz) {
+
+          fsrv->use_shdmen_fuzz = 1;
+          if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
+
+          if ((status & FS_OPT_AUTODICT) == 0) {
+
+            u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+            if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
+
+              FATAL("Writing to forkserver failed.");
+
+            }
+
+          }
+
+        }
+
+      }
+
       if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
 
         u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
@@ -490,7 +512,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
         if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) {
 
           // this is not afl-fuzz - we deny and return
-          status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT));
+          if (fsrv->use_shdmen_fuzz)
+            status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
+          else
+            status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
           if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
 
             FATAL("Writing to forkserver failed.");
@@ -749,39 +774,48 @@ static void afl_fsrv_kill(afl_forkserver_t *fsrv) {
 
 void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 
-  s32 fd = fsrv->out_fd;
+  if (fsrv->shdmem_fuzz) {
 
-  if (fsrv->out_file) {
+    memcpy(fsrv->shdmem_fuzz, buf, len);
+    fsrv->shdmem_fuzz_len = len;
 
-    if (fsrv->no_unlink) {
+  } else {
 
-      fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    s32 fd = fsrv->out_fd;
 
-    } else {
+    if (fsrv->out_file) {
 
-      unlink(fsrv->out_file);                             /* Ignore errors. */
-      fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
+      if (fsrv->no_unlink) {
 
-    }
+        fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
 
-    if (fd < 0) { PFATAL("Unable to create '%s'", fsrv->out_file); }
+      } else {
 
-  } else {
+        unlink(fsrv->out_file);                           /* Ignore errors. */
+        fd = open(fsrv->out_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
 
-    lseek(fd, 0, SEEK_SET);
+      }
 
-  }
+      if (fd < 0) { PFATAL("Unable to create '%s'", fsrv->out_file); }
 
-  ck_write(fd, buf, len, fsrv->out_file);
+    } else {
 
-  if (!fsrv->out_file) {
+      lseek(fd, 0, SEEK_SET);
 
-    if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
-    lseek(fd, 0, SEEK_SET);
+    }
 
-  } else {
+    ck_write(fd, buf, len, fsrv->out_file);
 
-    close(fd);
+    if (!fsrv->out_file) {
+
+      if (ftruncate(fd, len)) { PFATAL("ftruncate() failed"); }
+      lseek(fd, 0, SEEK_SET);
+
+    } else {
+
+      close(fd);
+
+    }
 
   }
 
@@ -795,6 +829,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   s32 res;
   u32 exec_ms;
+  u32 write_value = fsrv->last_run_timed_out;
 
   /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
      must prevent any earlier operations from venturing into that
@@ -804,10 +839,12 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
 
   MEM_BARRIER();
 
+  if (fsrv->shdmem_fuzz_len) write_value += (fsrv->shdmem_fuzz_len << 8);
+
   /* we have the fork server (or faux server) up and running
   First, tell it if the previous run timed out. */
 
-  if ((res = write(fsrv->fsrv_ctl_fd, &fsrv->last_run_timed_out, 4)) != 4) {
+  if ((res = write(fsrv->fsrv_ctl_fd, &write_value, 4)) != 4) {
 
     if (*stop_soon_p) { return 0; }
     RPFATAL(res, "Unable to request new process from fork server (OOM?)");
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index dd85a8f4..9349fefe 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -2153,6 +2153,30 @@ void check_binary(afl_state_t *afl, u8 *fname) {
     OKF(cPIN "Persistent mode binary detected.");
     setenv(PERSIST_ENV_VAR, "1", 1);
     afl->persistent_mode = 1;
+    // do not fail if we can not get the fuzzing shared mem
+    if ((afl->shm_fuzz = calloc(1, sizeof(sharedmem_t)))) {
+
+      // we need to set the dumb mode to not overwrite the SHM_ENV_VAR
+      if ((afl->fsrv.shdmem_fuzz = afl_shm_init(afl->shm_fuzz, MAX_FILE, 1))) {
+
+#ifdef USEMMAP
+        setenv(SHM_FUZZ_ENV_VAR, afl->shm_fuzz->g_shm_file_path, 1);
+#else
+        u8 *shm_str;
+        shm_str = alloc_printf("%d", afl->shm_fuzz->shm_id);
+        setenv(SHM_FUZZ_ENV_VAR, shm_str, 1);
+        ck_free(shm_str);
+#endif
+        afl->fsrv.support_shdmen_fuzz = 1;
+
+      } else {
+
+        free(afl->shm_fuzz);
+        afl->shm_fuzz = NULL;
+
+      }
+
+    }
 
   } else if (getenv("AFL_PERSISTENT")) {
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 8a1f02a7..04450363 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -231,6 +231,16 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
     afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
                    afl->afl_env.afl_debug_child_output);
 
+    if (afl->fsrv.support_shdmen_fuzz && !afl->fsrv.use_shdmen_fuzz) {
+
+      afl_shm_deinit(afl->shm_fuzz);
+      free(afl->shm_fuzz);
+      afl->shm_fuzz = NULL;
+      afl->fsrv.support_shdmen_fuzz = 0;
+      afl->fsrv.shdmem_fuzz = NULL;
+
+    }
+
   }
 
   if (q->exec_cksum) {
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index c07371a8..e024e9a4 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1379,6 +1379,14 @@ stop_fuzzing:
   destroy_extras(afl);
   destroy_custom_mutators(afl);
   afl_shm_deinit(&afl->shm);
+
+  if (afl->shm_fuzz) {
+
+    afl_shm_deinit(afl->shm_fuzz);
+    free(afl->shm_fuzz);
+
+  }
+
   afl_fsrv_deinit(&afl->fsrv);
   if (afl->orig_cmdline) { ck_free(afl->orig_cmdline); }
   ck_free(afl->fsrv.target_path);