about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2020-05-29 14:35:05 +0200
committerGitHub <noreply@github.com>2020-05-29 14:35:05 +0200
commit710dda522186310a7fb4e3b6a05cae0b28fa619e (patch)
treef96fcfe756fe5e6e0dde11be8df8b3df9f654952 /src
parent6892018142cc21ba9a0744c0757d39f21e9b66bc (diff)
parentc3b864d8d4dfaf148158a689df0c5ddf4bcc1f32 (diff)
downloadafl++-710dda522186310a7fb4e3b6a05cae0b28fa619e.tar.gz
Merge pull request #374 from AFLplusplus/dev
Dev
Diffstat (limited to 'src')
-rw-r--r--src/afl-as.c10
-rw-r--r--src/afl-common.c2
-rw-r--r--src/afl-forkserver.c83
-rw-r--r--src/afl-fuzz-init.c80
-rw-r--r--src/afl-fuzz-mutators.c3
-rw-r--r--src/afl-fuzz-one.c34
-rw-r--r--src/afl-fuzz-run.c129
-rw-r--r--src/afl-fuzz.c30
8 files changed, 279 insertions, 92 deletions
diff --git a/src/afl-as.c b/src/afl-as.c
index 4809a731..f16d6060 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -232,8 +232,8 @@ static void edit_params(int argc, char **argv) {
 
   }
 
-  modified_file =
-      alloc_printf("%s/.afl-%u-%u.s", tmp_dir, (u32)getpid(), (u32)time(NULL));
+  modified_file = alloc_printf("%s/.afl-%u-%u-%u.s", tmp_dir, (u32)getpid(),
+                               (u32)time(NULL), (u32)random());
 
 wrap_things_up:
 
@@ -531,7 +531,7 @@ static void add_instrumentation(void) {
 int main(int argc, char **argv) {
 
   s32 pid;
-  u32 rand_seed;
+  u32 rand_seed, i, j;
   int status;
   u8 *inst_ratio_str = getenv("AFL_INST_RATIO");
 
@@ -590,6 +590,10 @@ int main(int argc, char **argv) {
   gettimeofday(&tv, &tz);
 
   rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
+  // in fast systems where pids can repeat in the same seconds we need this
+  for (i = 1; i < argc; i++)
+    for (j = 0; j < strlen(argv[i]); j++)
+      rand_seed += argv[i][j];
 
   srandom(rand_seed);
 
diff --git a/src/afl-common.c b/src/afl-common.c
index 808c9812..1bb58a60 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -67,7 +67,7 @@ char *afl_environment_variables[] = {
     "AFL_LLVM_SKIPSINGLEBLOCK", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK",
     "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW",
     "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES",
-    "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR",
+    "AFL_LLVM_LAF_ALL", "AFL_LLVM_LAF_TRANSFORM_COMPARES", "AFL_LLVM_MAP_ADDR",
     "AFL_LLVM_MAP_DYNAMIC", "AFL_LLVM_NGRAM_SIZE", "AFL_NGRAM_SIZE",
     "AFL_LLVM_NOT_ZERO", "AFL_LLVM_WHITELIST", "AFL_LLVM_SKIP_NEVERZERO",
     "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID",
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 1c0ba349..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.");
@@ -677,9 +702,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     SAYF("\n" cLRD "[-] " cRST
          "Hmm, looks like the target binary terminated before we could"
-         "complete a handshake with the injected code.\n"
+         " complete a handshake with the injected code.\n"
          "If the target was compiled with afl-clang-lto then recompiling with"
-         "AFL_LLVM_MAP_DYNAMIC might solve your problem.\n"
+         " AFL_LLVM_MAP_DYNAMIC might solve your problem.\n"
          "Otherwise there is a horrible bug in the fuzzer.\n"
          "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
 
@@ -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 613d1437..9349fefe 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -1315,6 +1315,39 @@ dir_cleanup_failed:
 
 }
 
+/* If this is a -S slave, ensure a -M master is running, if a master is
+   running when another master is started then warn */
+
+int check_master_exists(afl_state_t *afl) {
+
+  DIR *          sd;
+  struct dirent *sd_ent;
+  u8 *           fn;
+
+  sd = opendir(afl->sync_dir);
+  if (!sd) { return 0; }
+
+  while ((sd_ent = readdir(sd))) {
+
+    /* Skip dot files and our own output directory. */
+
+    if (sd_ent->d_name[0] == '.' || !strcmp(afl->sync_id, sd_ent->d_name)) {
+
+      continue;
+
+    }
+
+    fn = alloc_printf("%s/%s/is_master", afl->sync_dir, sd_ent->d_name);
+    int res = access(fn, F_OK);
+    free(fn);
+    if (res == 0) return 1;
+
+  }
+
+  return 0;
+
+}
+
 /* Prepare output directories and fds. */
 
 void setup_dirs_fds(afl_state_t *afl) {
@@ -1330,19 +1363,6 @@ void setup_dirs_fds(afl_state_t *afl) {
 
   }
 
-  /*
-    if (afl->is_master) {
-
-      u8 *x = alloc_printf("%s/%s/is_master", afl->sync_dir, afl->sync_id);
-      int fd = open(x, O_CREAT | O_RDWR, 0644);
-      if (fd < 0) FATAL("cannot create %s", x);
-      free(x);
-      close(fd);
-
-    }
-
-  */
-
   if (mkdir(afl->out_dir, 0700)) {
 
     if (errno != EEXIST) { PFATAL("Unable to create '%s'", afl->out_dir); }
@@ -1372,6 +1392,16 @@ void setup_dirs_fds(afl_state_t *afl) {
 
   }
 
+  if (afl->is_master) {
+
+    u8 *x = alloc_printf("%s/is_master", afl->out_dir);
+    int fd = open(x, O_CREAT | O_RDWR, 0644);
+    if (fd < 0) FATAL("cannot create %s", x);
+    free(x);
+    close(fd);
+
+  }
+
   /* Queue directory for any starting & discovered paths. */
 
   tmp = alloc_printf("%s/queue", afl->out_dir);
@@ -2123,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-mutators.c b/src/afl-fuzz-mutators.c
index 87cb86fa..29e10d02 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -108,9 +108,6 @@ void setup_custom_mutators(afl_state_t *afl) {
 
 #endif
 
-  if (afl->post_library_mutator)
-    list_append(&afl->custom_mutator_list, afl->post_library_mutator);
-
 }
 
 void destroy_custom_mutators(afl_state_t *afl) {
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index ddd15c84..56f16b4c 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -4250,11 +4250,27 @@ pacemaker_fuzzing:
           u64 temp_temp_puppet =
               afl->queued_paths + afl->unique_crashes - temp_total_found;
           afl->total_puppet_find = afl->total_puppet_find + temp_temp_puppet;
-          for (i = 0; i < operator_num; ++i) {
 
-            if (MOpt_globals.cycles_v2[i] > MOpt_globals.cycles_v3[i]) {
+          if (MOpt_globals.is_pilot_mode) {
+
+            for (i = 0; i < operator_num; ++i) {
+
+              if (MOpt_globals.cycles_v2[i] > MOpt_globals.cycles_v3[i]) {
+
+                MOpt_globals.finds_v2[i] += temp_temp_puppet;
 
-              MOpt_globals.finds_v2[i] += temp_temp_puppet;
+              }
+
+            }
+
+          } else {
+
+            for (i = 0; i < operator_num; i++) {
+
+              if (afl->core_operator_cycles_puppet_v2[i] >
+                  afl->core_operator_cycles_puppet_v3[i])
+
+                afl->core_operator_finds_puppet_v2[i] += temp_temp_puppet;
 
             }
 
@@ -4437,7 +4453,6 @@ pacemaker_fuzzing:
 
         afl->total_pacemaker_time += *MOpt_globals.pTime;
         *MOpt_globals.pTime = 0;
-        afl->temp_puppet_find = afl->total_puppet_find;
         new_hit_cnt = afl->queued_paths + afl->unique_crashes;
 
         if (MOpt_globals.is_pilot_mode) {
@@ -4448,6 +4463,7 @@ pacemaker_fuzzing:
 
         }
 
+        afl->temp_puppet_find = afl->total_puppet_find;
         u64 temp_stage_finds_puppet = 0;
         for (i = 0; i < operator_num; ++i) {
 
@@ -4530,6 +4546,16 @@ pacemaker_fuzzing:
 
         } else {
 
+          for (i = 0; i < operator_num; i++) {
+
+            afl->core_operator_finds_puppet[i] =
+                afl->core_operator_finds_puppet_v2[i];
+            afl->core_operator_cycles_puppet[i] =
+                afl->core_operator_cycles_puppet_v2[i];
+            temp_stage_finds_puppet += afl->core_operator_finds_puppet[i];
+
+          }
+
           afl->key_module = 2;
 
           afl->old_hit_count = new_hit_cnt;
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index bbcd9a99..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) {
@@ -373,7 +383,8 @@ void sync_fuzzers(afl_state_t *afl) {
 
   DIR *          sd;
   struct dirent *sd_ent;
-  u32            sync_cnt = 0;
+  u32            sync_cnt = 0, synced = 0, entries = 0;
+  u8             path[PATH_MAX];
 
   sd = opendir(afl->sync_dir);
   if (!sd) { PFATAL("Unable to open '%s'", afl->sync_dir); }
@@ -386,10 +397,8 @@ void sync_fuzzers(afl_state_t *afl) {
 
   while ((sd_ent = readdir(sd))) {
 
-    DIR *          qd;
-    struct dirent *qd_ent;
-    u8 *           qd_path, *qd_synced_path;
-    u32            min_accept = 0, next_min_accept;
+    u8  qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
+    u32 min_accept = 0, next_min_accept;
 
     s32 id_fd;
 
@@ -401,35 +410,52 @@ void sync_fuzzers(afl_state_t *afl) {
 
     }
 
-    /*
-        // a slave only syncs from a master, a master syncs from everyone
-        if (likely(afl->is_slave)) {
+    entries++;
+
+    // a slave only syncs from a master, a master syncs from everyone
+    if (likely(afl->is_slave)) {
 
-          u8 x = alloc_printf("%s/%s/is_master", afl->sync_dir, sd_ent->d_name);
-          int res = access(x, F_OK);
-          free(x);
-          if (res != 0)
-            continue;
+      sprintf(qd_path, "%s/%s/is_master", afl->sync_dir, sd_ent->d_name);
+      int res = access(qd_path, F_OK);
+      if (unlikely(afl->is_master)) {  // an elected temporary master
+
+        if (likely(res == 0)) {  // there is another master? downgrade.
+
+          afl->is_master = 0;
+          sprintf(qd_path, "%s/is_master", afl->out_dir);
+          unlink(qd_path);
 
         }
 
-    */
+      } else {
+
+        if (likely(res != 0)) { continue; }
+
+      }
+
+    }
+
+    synced++;
 
     /* Skip anything that doesn't have a queue/ subdirectory. */
 
-    qd_path = alloc_printf("%s/%s/queue", afl->sync_dir, sd_ent->d_name);
+    sprintf(qd_path, "%s/%s/queue", afl->sync_dir, sd_ent->d_name);
+
+    struct dirent **namelist = NULL;
+    int             m = 0, n, o;
 
-    if (!(qd = opendir(qd_path))) {
+    n = scandir(qd_path, &namelist, NULL, alphasort);
 
-      ck_free(qd_path);
+    if (n < 1) {
+
+      if (namelist) free(namelist);
       continue;
 
     }
 
     /* Retrieve the ID of the last seen test case. */
 
-    qd_synced_path =
-        alloc_printf("%s/.synced/%s", afl->out_dir, sd_ent->d_name);
+    sprintf(qd_synced_path, "%s/.synced/%s", afl->out_dir, sd_ent->d_name);
 
     id_fd = open(qd_synced_path, O_RDWR | O_CREAT, 0600);
 
@@ -454,42 +480,42 @@ void sync_fuzzers(afl_state_t *afl) {
     /* For every file queued by this fuzzer, parse ID and see if we have
        looked at it before; exec a test case if not. */
 
-    while ((qd_ent = readdir(qd))) {
+    u8 entry[12];
+    sprintf(entry, "id:%06u", next_min_accept);
+    while (m < n) {
 
-      u8 *        path;
-      s32         fd;
-      struct stat st;
+      if (memcmp(namelist[m]->d_name, entry, 9)) {
+
+        m++;
 
-      if (qd_ent->d_name[0] == '.' ||
-          sscanf(qd_ent->d_name, CASE_PREFIX "%06u", &afl->syncing_case) != 1 ||
-          afl->syncing_case < min_accept) {
+      } else {
 
-        continue;
+        break;
 
       }
 
-      /* OK, sounds like a new one. Let's give it a try. */
+    }
 
-      if (afl->syncing_case >= next_min_accept) {
+    if (m >= n) { goto close_sync; }  // nothing new
+    o = n - 1;
 
-        next_min_accept = afl->syncing_case + 1;
+    while (o >= m) {
 
-      }
+      s32         fd;
+      struct stat st;
 
-      path = alloc_printf("%s/%s", qd_path, qd_ent->d_name);
+      sprintf(path, "%s/%s", qd_path, namelist[o]->d_name);
+      afl->syncing_case = next_min_accept;
+      next_min_accept++;
+      o--;
 
       /* Allow this to fail in case the other fuzzer is resuming or so... */
 
       fd = open(path, O_RDONLY);
 
-      if (fd < 0) {
-
-        ck_free(path);
-        continue;
+      if (fd < 0) { continue; }
 
-      }
-
-      if (fstat(fd, &st)) { PFATAL("fstat() failed"); }
+      if (fstat(fd, &st)) { WARNF("fstat() failed"); }
 
       /* Ignore zero-sized or oversized files. */
 
@@ -516,11 +542,8 @@ void sync_fuzzers(afl_state_t *afl) {
 
         munmap(mem, st.st_size);
 
-        if (!(afl->stage_cur++ % afl->stats_update_freq)) { show_stats(afl); }
-
       }
 
-      ck_free(path);
       close(fd);
 
     }
@@ -529,14 +552,30 @@ void sync_fuzzers(afl_state_t *afl) {
 
   close_sync:
     close(id_fd);
-    closedir(qd);
-    ck_free(qd_path);
-    ck_free(qd_synced_path);
+    if (n > 0)
+      for (m = 0; m < n; m++)
+        free(namelist[m]);
+    free(namelist);
 
   }
 
   closedir(sd);
 
+  // If we are a slave and no master was found to sync then become the master
+  if (unlikely(synced == 0) && likely(entries) && likely(afl->is_slave)) {
+
+    // there is a small race condition here that another slave runs at the same
+    // time. If so, the first temporary master running again will demote
+    // themselves so this is not an issue
+
+    u8 path[PATH_MAX];
+    afl->is_master = 1;
+    sprintf(path, "%s/is_master", afl->out_dir);
+    int fd = open(path, O_CREAT | O_RDWR, 0644);
+    if (fd >= 0) { close(fd); }
+
+  }
+
 }
 
 /* Trim all new test cases to save cycles when doing deterministic checks. The
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 8625c37c..e024e9a4 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -1065,8 +1065,22 @@ int main(int argc, char **argv_orig, char **envp) {
 
   init_count_class16();
 
+  if (afl->is_master && check_master_exists(afl) == 1) {
+
+    WARNF("it is wasteful to run more than one master!");
+    sleep(1);
+
+  }
+
   setup_dirs_fds(afl);
 
+  if (afl->is_slave && check_master_exists(afl) == 0) {
+
+    WARNF("no -M master found. You need to run one master!");
+    sleep(5);
+
+  }
+
   setup_custom_mutators(afl);
 
   setup_cmdline_file(afl, argv + optind);
@@ -1352,11 +1366,27 @@ stop_fuzzing:
        time_spent_working / afl->fsrv.total_execs);
   #endif
 
+  if (afl->is_master) {
+
+    u8 path[PATH_MAX];
+    sprintf(path, "%s/is_master", afl->out_dir);
+    unlink(path);
+
+  }
+
   fclose(afl->fsrv.plot_file);
   destroy_queue(afl);
   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);