about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c64
-rw-r--r--src/afl-common.c49
-rw-r--r--src/afl-forkserver.c259
-rw-r--r--src/afl-fuzz-python.c49
-rw-r--r--src/afl-fuzz-queue.c14
-rw-r--r--src/afl-fuzz-run.c10
-rw-r--r--src/afl-fuzz.c78
-rw-r--r--src/afl-showmap.c106
-rw-r--r--src/afl-tmin.c59
9 files changed, 523 insertions, 165 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 548956d8..5b122741 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -121,9 +121,9 @@ static void kill_child() {
 
 }
 
-static void classify_counts(u8 *mem) {
+static void classify_counts(u8 *mem, u32 mem_size) {
 
-  u32 i = map_size;
+  u32 i = mem_size;
 
   if (edges_only) {
 
@@ -222,7 +222,7 @@ static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
 
   }
 
-  classify_counts(fsrv.trace_bits);
+  classify_counts(fsrv.trace_bits, fsrv.map_size);
   total_execs++;
 
   if (stop_soon) {
@@ -768,6 +768,7 @@ static void usage(u8 *argv0) {
       "  -U            - use unicorn-based instrumentation (Unicorn mode)\n"
       "  -W            - use qemu-based instrumentation with Wine (Wine "
       "mode)\n"
+      "  -X            - use Nyx mode\n"
 #endif
       "\n"
 
@@ -814,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl_fsrv_init(&fsrv);
 
-  while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
 
     switch (opt) {
 
@@ -966,6 +967,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'Y':  // fallthough
+#ifdef __linux__
+      case 'X':                                                 /* NYX mode */
+
+        if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+        fsrv.nyx_mode = 1;
+        fsrv.nyx_parent = true;
+        fsrv.nyx_standalone = true;
+
+        break;
+#else
+      case 'X':
+        FATAL("Nyx mode is only availabe on linux...");
+        break;
+#endif
+
       case 'h':
         usage(argv[0]);
         return -1;
@@ -997,7 +1015,21 @@ int main(int argc, char **argv_orig, char **envp) {
 
   set_up_environment(argv);
 
+#ifdef __linux__
+  if (!fsrv.nyx_mode) {
+
+    fsrv.target_path = find_binary(argv[optind]);
+
+  } else {
+
+    fsrv.target_path = ck_strdup(argv[optind]);
+
+  }
+
+#else
   fsrv.target_path = find_binary(argv[optind]);
+#endif
+
   fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
   detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
   signal(SIGALRM, kill_child);
@@ -1020,6 +1052,26 @@ int main(int argc, char **argv_orig, char **envp) {
 
     use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
 
+#ifdef __linux__
+
+  } else if (fsrv.nyx_mode) {
+
+    fsrv.nyx_id = 0;
+
+    u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+    fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+    if (fsrv.nyx_handlers == NULL) {
+
+      FATAL("failed to initialize libnyx.so...");
+
+    }
+
+    fsrv.nyx_use_tmp_workdir = true;
+    fsrv.nyx_bind_cpu_id = 0;
+
+    use_argv = argv + optind;
+#endif
+
   } else {
 
     use_argv = argv + optind;
@@ -1045,7 +1097,11 @@ int main(int argc, char **argv_orig, char **envp) {
       &fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
 
   read_initial_file();
+#ifdef __linux__
+  if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
+#else
   (void)check_binary_signatures(fsrv.target_path);
+#endif
 
   ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
        mem_limit, exec_tmout, edges_only ? ", edges only" : "");
diff --git a/src/afl-common.c b/src/afl-common.c
index 86226c9f..a5c48e80 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -1359,3 +1359,52 @@ s32 create_file(u8 *fn) {
 
 }
 
+#ifdef __linux__
+
+/* Nyx requires a tmp workdir to access specific files (such as mmapped files,
+ * etc.). This helper function basically creates both a path to a tmp workdir
+ * and the workdir itself. If the environment variable TMPDIR is set, we use
+ * that as the base directory, otherwise we use /tmp. */
+char *create_nyx_tmp_workdir(void) {
+
+  char *tmpdir = getenv("TMPDIR");
+
+  if (!tmpdir) { tmpdir = "/tmp"; }
+
+  char *nyx_out_dir_path =
+      alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid());
+
+  if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); }
+
+  return nyx_out_dir_path;
+
+}
+
+/* Vice versa, we remove the tmp workdir for nyx with this helper function. */
+void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) {
+
+  char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path);
+
+  if (access(workdir_path, R_OK) == 0) {
+
+    if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) {
+
+      WARNF("Unable to remove nyx workdir (%s)", workdir_path);
+
+    }
+
+  }
+
+  if (rmdir(nyx_out_dir_path)) {
+
+    WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path);
+
+  }
+
+  ck_free(workdir_path);
+  ck_free(nyx_out_dir_path);
+
+}
+
+#endif
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 5aa4c2ff..aa8c8622 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -49,6 +49,134 @@
 #include <sys/select.h>
 #include <sys/stat.h>
 
+#ifdef __linux__
+  #include <dlfcn.h>
+
+/* function to load nyx_helper function from libnyx.so */
+
+nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
+
+  void                 *handle;
+  nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
+
+  ACTF("Trying to load libnyx.so plugin...");
+  handle = dlopen((char *)libnyx_binary, RTLD_NOW);
+  if (!handle) { goto fail; }
+
+  plugin->nyx_config_load = dlsym(handle, "nyx_config_load");
+  if (plugin->nyx_config_load == NULL) { goto fail; }
+
+  plugin->nyx_config_set_workdir_path =
+      dlsym(handle, "nyx_config_set_workdir_path");
+  if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; }
+
+  plugin->nyx_config_set_input_buffer_size =
+      dlsym(handle, "nyx_config_set_input_buffer_size");
+  if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; }
+
+  plugin->nyx_config_set_input_buffer_write_protection =
+      dlsym(handle, "nyx_config_set_input_buffer_write_protection");
+  if (plugin->nyx_config_set_input_buffer_write_protection == NULL) {
+
+    goto fail;
+
+  }
+
+  plugin->nyx_config_set_hprintf_fd =
+      dlsym(handle, "nyx_config_set_hprintf_fd");
+  if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; }
+
+  plugin->nyx_config_set_process_role =
+      dlsym(handle, "nyx_config_set_process_role");
+  if (plugin->nyx_config_set_process_role == NULL) { goto fail; }
+
+  plugin->nyx_config_set_reuse_snapshot_path =
+      dlsym(handle, "nyx_config_set_reuse_snapshot_path");
+  if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; }
+
+  plugin->nyx_new = dlsym(handle, "nyx_new");
+  if (plugin->nyx_new == NULL) { goto fail; }
+
+  plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
+  if (plugin->nyx_shutdown == NULL) { goto fail; }
+
+  plugin->nyx_option_set_reload_mode =
+      dlsym(handle, "nyx_option_set_reload_mode");
+  if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
+
+  plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
+  if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
+
+  plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
+  if (plugin->nyx_option_apply == NULL) { goto fail; }
+
+  plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
+  if (plugin->nyx_set_afl_input == NULL) { goto fail; }
+
+  plugin->nyx_exec = dlsym(handle, "nyx_exec");
+  if (plugin->nyx_exec == NULL) { goto fail; }
+
+  plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
+  if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
+
+  plugin->nyx_get_bitmap_buffer_size =
+      dlsym(handle, "nyx_get_bitmap_buffer_size");
+  if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
+
+  plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
+  if (plugin->nyx_get_aux_string == NULL) { goto fail; }
+
+  plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir");
+  if (plugin->nyx_remove_work_dir == NULL) { goto fail; }
+
+  OKF("libnyx plugin is ready!");
+  return plugin;
+
+fail:
+
+  FATAL("failed to load libnyx: %s\n", dlerror());
+  ck_free(plugin);
+  return NULL;
+
+}
+
+void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
+
+  if (fsrv->nyx_mode) {
+
+    if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); }
+
+    /* check if we actually got a valid nyx runner */
+    if (fsrv->nyx_runner) {
+
+      fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+
+    }
+
+    /* if we have use a tmp work dir we need to remove it */
+    if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) {
+
+      remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path);
+
+    }
+
+  }
+
+}
+
+  /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp
+   * files) before exiting. Used before "afl_fsrv_killall()" is registered as
+   * an atexit() handler. */
+  #define NYX_PRE_FATAL(fsrv, x...) \
+    do {                            \
+                                    \
+      afl_nyx_runner_kill(fsrv);    \
+      FATAL(x);                     \
+                                    \
+    } while (0)
+
+#endif
+
 /**
  * The correct fds for reading and writing pipes
  */
@@ -84,6 +212,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
   fsrv->nyx_runner = NULL;
   fsrv->nyx_id = 0xFFFFFFFF;
   fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
+  fsrv->nyx_use_tmp_workdir = false;
+  fsrv->nyx_tmp_workdir_path = NULL;
 #endif
 
   // this structure needs default so we initialize it if this was not done
@@ -397,40 +527,119 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
     if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
 
-    if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); }
+    if (fsrv->nyx_use_tmp_workdir) {
+
+      fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir();
+      fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path;
+
+    } else {
+
+      if (fsrv->out_dir_path == NULL) {
+
+        NYX_PRE_FATAL(fsrv, "Nyx workdir path not found...");
+
+      }
+
+    }
+
+    /* libnyx expects an absolute path */
+    char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL);
+    if (outdir_path_absolute == NULL) {
 
-    char *x = alloc_printf("%s/workdir", fsrv->out_dir_path);
+      NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ...");
 
-    if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); }
+    }
+
+    char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute);
+
+    if (fsrv->nyx_id == 0xFFFFFFFF) {
+
+      NYX_PRE_FATAL(fsrv, "Nyx ID is not set...");
+
+    }
 
     if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) {
 
-      FATAL("Nyx CPU ID is not set...");
+      NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set...");
 
     }
 
+    void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
+
+    fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
+    fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE);
+    fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
+                                                                     true);
+
     if (fsrv->nyx_standalone) {
 
-      fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(
-          fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+      fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone);
 
     } else {
 
       if (fsrv->nyx_parent) {
 
-        fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_parent(
-            fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+        fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent);
 
       } else {
 
-        fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_child(
-            fsrv->target_path, x, fsrv->nyx_bind_cpu_id, fsrv->nyx_id);
+        fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child);
+
+      }
+
+    }
+
+    if (getenv("NYX_REUSE_SNAPSHOT") != NULL) {
+
+      if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+
+        NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist");
+
+      }
+
+      /* stupid sanity check to avoid passing an empty or invalid snapshot
+       * directory */
+      char *snapshot_file_path =
+          alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT"));
+      if (access(snapshot_file_path, R_OK) == -1) {
+
+        NYX_PRE_FATAL(
+            fsrv,
+            "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot");
+
+      }
+
+      ck_free(snapshot_file_path);
+
+      /* another sanity check to avoid passing a snapshot directory that is
+       * located in the current workdir (the workdir will be wiped by libnyx on
+       * startup) */
+      char *workdir_snapshot_path =
+          alloc_printf("%s/workdir/snapshot", outdir_path_absolute);
+      char *reuse_snapshot_path_real =
+          realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL);
+
+      if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) {
+
+        NYX_PRE_FATAL(fsrv,
+                      "NYX_REUSE_SNAPSHOT path is located in current workdir "
+                      "(use another output directory)");
 
       }
 
+      ck_free(reuse_snapshot_path_real);
+      ck_free(workdir_snapshot_path);
+
+      fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(
+          nyx_config, getenv("NYX_REUSE_SNAPSHOT"));
+
     }
 
-    ck_free(x);
+    fsrv->nyx_runner =
+        fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id);
+
+    ck_free(workdir_path);
+    ck_free(outdir_path_absolute);
 
     if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); }
 
@@ -458,15 +667,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
     switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
 
       case Abort:
-        fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
-        FATAL("Error: Nyx abort occured...");
+        NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured...");
         break;
       case IoError:
-        FATAL("Error: QEMU-Nyx has died...");
+        NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died...");
         break;
       case Error:
-        fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
-        FATAL("Error: Nyx runtime error has occured...");
+        NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured...");
         break;
       default:
         break;
@@ -476,7 +683,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
     /* autodict in Nyx mode */
     if (!ignore_autodict) {
 
-      x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
+      char *x =
+          alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
       int nyx_autodict_fd = open(x, O_RDONLY);
       ck_free(x);
 
@@ -489,8 +697,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
           u8 *dict = ck_alloc(f_len);
           if (dict == NULL) {
 
-            FATAL("Could not allocate %u bytes of autodictionary memory",
-                  f_len);
+            NYX_PRE_FATAL(
+                fsrv, "Could not allocate %u bytes of autodictionary memory",
+                f_len);
 
           }
 
@@ -507,7 +716,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
 
             } else {
 
-              FATAL(
+              NYX_PRE_FATAL(
+                  fsrv,
                   "Reading autodictionary fail at position %u with %u bytes "
                   "left.",
                   offset, len);
@@ -1194,13 +1404,7 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
   fsrv->child_pid = -1;
 
 #ifdef __linux__
-  if (fsrv->nyx_mode) {
-
-    free(fsrv->nyx_aux_string);
-    fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
-
-  }
-
+  afl_nyx_runner_kill(fsrv);
 #endif
 
 }
@@ -1377,7 +1581,6 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
         FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
         break;
       case Abort:
-        fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
         FATAL("Error: Nyx abort occured...");
       case IoError:
         if (*stop_soon_p) {
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 673e5a6c..7dad0770 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -219,11 +219,14 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
 
   if (py_module != NULL) {
 
-    u8 py_notrim = 0, py_idx;
-    /* init, required */
+    u8 py_notrim = 0;
     py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
-    if (!py_functions[PY_FUNC_INIT])
-      FATAL("init function not found in python module");
+    if (!py_functions[PY_FUNC_INIT]) {
+
+      WARNF("init function not found in python module");
+
+    }
+
     py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
     if (!py_functions[PY_FUNC_FUZZ])
       py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
@@ -231,12 +234,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
         PyObject_GetAttrString(py_module, "describe");
     py_functions[PY_FUNC_FUZZ_COUNT] =
         PyObject_GetAttrString(py_module, "fuzz_count");
-    if (!py_functions[PY_FUNC_FUZZ]) {
-
-      WARNF("fuzz function not found in python module");
-
-    }
-
     py_functions[PY_FUNC_POST_PROCESS] =
         PyObject_GetAttrString(py_module, "post_process");
     py_functions[PY_FUNC_INIT_TRIM] =
@@ -263,36 +260,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
     if (!py_functions[PY_FUNC_DEINIT])
       WARNF("deinit function not found in python module");
 
-    for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
-
-      if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
-
-        if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
-
-          // Implementing the trim API is optional for now
-          if (PyErr_Occurred()) { PyErr_Print(); }
-          py_notrim = 1;
-
-        } else if (py_idx >= PY_OPTIONAL) {
-
-          // Only _init and _deinit are not optional currently
-
-          if (PyErr_Occurred()) { PyErr_Print(); }
-
-        } else {
-
-          fprintf(stderr,
-                  "Cannot find/call function with index %d in external "
-                  "Python module.\n",
-                  py_idx);
-          return NULL;
-
-        }
-
-      }
-
-    }
-
     if (py_notrim) {
 
       py_functions[PY_FUNC_INIT_TRIM] = NULL;
@@ -345,6 +312,8 @@ static void init_py(afl_state_t *afl, py_mutator_t *py_mutator,
 
   (void)afl;
 
+  if (py_mutator->py_functions[PY_FUNC_INIT] == NULL) { return; }
+
   PyObject *py_args, *py_value;
 
   /* Provide the init function a seed for the Python RNG */
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 6fc3c743..8ad7cd97 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -149,21 +149,15 @@ void create_alias_table(afl_state_t *afl) {
 
     }
 
-    if (unlikely(afl->prefer_new) && afl->queued_discovered) {
+    if (unlikely(afl->schedule == MMOPT) && afl->queued_discovered) {
 
-      double avg_weight = sum / active;
+      u32 cnt = afl->queued_discovered >= 5 ? 5 : afl->queued_discovered;
 
-      for (i = n - afl->queued_discovered; i < n; i++) {
+      for (i = n - cnt; i < n; i++) {
 
         struct queue_entry *q = afl->queue_buf[i];
 
-        if (likely(!q->disabled) && q->weight > avg_weight) {
-
-          double prev_weight = q->weight;
-          q->weight *= (2.0 * (i / n));
-          sum += (q->weight - prev_weight);
-
-        }
+        if (likely(!q->disabled)) { q->weight *= 2.0; }
 
       }
 
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index f5425011..4d56f3a7 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -133,7 +133,15 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
 
     }
 
-    if (new_mem != *mem) { *mem = new_mem; }
+    if (new_mem != *mem && new_mem != NULL && new_size > 0) {
+
+      u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
+      if (unlikely(!new_buf)) { PFATAL("alloc"); }
+      *mem = new_buf;
+      memcpy(*mem, new_mem, new_size);
+      afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+
+    }
 
     if (unlikely(afl->custom_mutators_count)) {
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index a0c322da..f6628851 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -132,7 +132,6 @@ static void usage(u8 *argv0, int more_help) {
       "                  fast(default), explore, exploit, seek, rare, mmopt, "
       "coe, lin\n"
       "                  quad -- see docs/FAQ.md for more information\n"
-      "  -z            - prefer new coverage findings when fuzzing\n"
       "  -f file       - location read by the fuzzed program (default: stdin "
       "or @@)\n"
       "  -t msec       - timeout for each run (auto-scaled, default %u ms). "
@@ -436,69 +435,6 @@ static void fasan_check_afl_preload(char *afl_preload) {
 
 }
 
-  #ifdef __linux__
-    #include <dlfcn.h>
-
-nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
-
-  void                 *handle;
-  nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
-
-  ACTF("Trying to load libnyx.so plugin...");
-  handle = dlopen((char *)libnyx_binary, RTLD_NOW);
-  if (!handle) { goto fail; }
-
-  plugin->nyx_new = dlsym(handle, "nyx_new");
-  if (plugin->nyx_new == NULL) { goto fail; }
-
-  plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent");
-  if (plugin->nyx_new_parent == NULL) { goto fail; }
-
-  plugin->nyx_new_child = dlsym(handle, "nyx_new_child");
-  if (plugin->nyx_new_child == NULL) { goto fail; }
-
-  plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
-  if (plugin->nyx_shutdown == NULL) { goto fail; }
-
-  plugin->nyx_option_set_reload_mode =
-      dlsym(handle, "nyx_option_set_reload_mode");
-  if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
-
-  plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
-  if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
-
-  plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
-  if (plugin->nyx_option_apply == NULL) { goto fail; }
-
-  plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
-  if (plugin->nyx_set_afl_input == NULL) { goto fail; }
-
-  plugin->nyx_exec = dlsym(handle, "nyx_exec");
-  if (plugin->nyx_exec == NULL) { goto fail; }
-
-  plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
-  if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
-
-  plugin->nyx_get_bitmap_buffer_size =
-      dlsym(handle, "nyx_get_bitmap_buffer_size");
-  if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
-
-  plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
-  if (plugin->nyx_get_aux_string == NULL) { goto fail; }
-
-  OKF("libnyx plugin is ready!");
-  return plugin;
-
-fail:
-
-  FATAL("failed to load libnyx: %s\n", dlerror());
-  free(plugin);
-  return NULL;
-
-}
-
-  #endif
-
 /* Main entry point */
 
 int main(int argc, char **argv_orig, char **envp) {
@@ -556,7 +492,7 @@ int main(int argc, char **argv_orig, char **envp) {
   while (
       (opt = getopt(
            argc, argv,
-           "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YzZ")) >
+           "+Ab:B:c:CdDe:E:hi:I:f:F:g:G:l:L:m:M:nNOo:p:RQs:S:t:T:UV:WXx:YZ")) >
       0) {
 
     switch (opt) {
@@ -569,10 +505,6 @@ int main(int argc, char **argv_orig, char **envp) {
         afl->max_length = atoi(optarg);
         break;
 
-      case 'z':
-        afl->prefer_new = 1;
-        break;
-
       case 'Z':
         afl->old_seed_selection = 1;
         break;
@@ -2254,14 +2186,6 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (!afl->pending_not_fuzzed || !valid_seeds) {
 
-  #ifdef __linux__
-    if (afl->fsrv.nyx_mode) {
-
-      afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
-
-    }
-
-  #endif
     FATAL("We need at least one valid input seed that does not crash!");
 
   }
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 29abeb13..df030672 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -434,6 +434,23 @@ static u32 read_file(u8 *in_file) {
 
 }
 
+#ifdef __linux__
+/* Execute the target application with an empty input (in Nyx mode). */
+static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) {
+
+  afl_fsrv_write_to_testcase(fsrv, NULL, 0);
+
+  if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+      FSRV_RUN_ERROR) {
+
+    FATAL("Error running target in Nyx mode");
+
+  }
+
+}
+
+#endif
+
 /* Execute target application. */
 
 static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
@@ -797,6 +814,7 @@ static void usage(u8 *argv0) {
       "  -W         - use qemu-based instrumentation with Wine (Wine mode)\n"
       "               (Not necessary, here for consistency with other afl-* "
       "tools)\n"
+      "  -X         - use Nyx mode\n"
 #endif
       "\n"
       "Other settings:\n"
@@ -875,7 +893,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) {
 
     switch (opt) {
 
@@ -1063,6 +1081,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'Y':  // fallthough
+#ifdef __linux__
+      case 'X':                                                 /* NYX mode */
+
+        if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+        fsrv->nyx_mode = 1;
+        fsrv->nyx_parent = true;
+        fsrv->nyx_standalone = true;
+
+        break;
+#else
+      case 'X':
+        FATAL("Nyx mode is only availabe on linux...");
+        break;
+#endif
+
       case 'b':
 
         /* Secret undocumented mode. Writes output in raw binary format
@@ -1134,7 +1169,21 @@ int main(int argc, char **argv_orig, char **envp) {
 
   set_up_environment(fsrv, argv);
 
+#ifdef __linux__
+  if (!fsrv->nyx_mode) {
+
+    fsrv->target_path = find_binary(argv[optind]);
+
+  } else {
+
+    fsrv->target_path = ck_strdup(argv[optind]);
+
+  }
+
+#else
   fsrv->target_path = find_binary(argv[optind]);
+#endif
+
   fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
 
   if (!quiet_mode) {
@@ -1190,6 +1239,27 @@ int main(int argc, char **argv_orig, char **envp) {
     use_argv =
         get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
 
+#ifdef __linux__
+
+  } else if (fsrv->nyx_mode) {
+
+    use_argv = ck_alloc(sizeof(char *) * (1));
+    use_argv[0] = argv[0];
+
+    fsrv->nyx_id = 0;
+
+    u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so");
+    fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+    if (fsrv->nyx_handlers == NULL) {
+
+      FATAL("failed to initialize libnyx.so...");
+
+    }
+
+    fsrv->nyx_use_tmp_workdir = true;
+    fsrv->nyx_bind_cpu_id = 0;
+#endif
+
   } else {
 
     use_argv = argv + optind;
@@ -1226,7 +1296,16 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+#ifdef __linux__
+  if (!fsrv->nyx_mode && in_dir) {
+
+    (void)check_binary_signatures(fsrv->target_path);
+
+  }
+
+#else
   if (in_dir) { (void)check_binary_signatures(fsrv->target_path); }
+#endif
 
   shm_fuzz = ck_alloc(sizeof(sharedmem_t));
 
@@ -1246,8 +1325,14 @@ int main(int argc, char **argv_orig, char **envp) {
   fsrv->shmem_fuzz_len = (u32 *)map;
   fsrv->shmem_fuzz = map + sizeof(u32);
 
-  configure_afl_kill_signals(
-      fsrv, NULL, NULL, (fsrv->qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
+  configure_afl_kill_signals(fsrv, NULL, NULL,
+                             (fsrv->qemu_mode || unicorn_mode
+#ifdef __linux__
+                              || fsrv->nyx_mode
+#endif
+                              )
+                                 ? SIGKILL
+                                 : SIGTERM);
 
   if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
 
@@ -1390,7 +1475,20 @@ int main(int argc, char **argv_orig, char **envp) {
     if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
       shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
 
-    showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+    if (!fsrv->nyx_mode) {
+
+#endif
+      showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+
+    } else {
+
+      showmap_run_target_nyx_mode(fsrv);
+
+    }
+
+#endif
     tcnt = write_results_to_file(fsrv, out_file);
     if (!quiet_mode) {
 
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index c0087f5f..e7442d1d 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -789,6 +789,7 @@ static void usage(u8 *argv0) {
       "mode)\n"
       "                  (Not necessary, here for consistency with other afl-* "
       "tools)\n"
+      "  -X            - use Nyx mode\n"
 #endif
       "\n"
 
@@ -845,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
 
-  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) {
+  while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) {
 
     switch (opt) {
 
@@ -1003,6 +1004,23 @@ int main(int argc, char **argv_orig, char **envp) {
 
         break;
 
+      case 'Y':  // fallthough
+#ifdef __linux__
+      case 'X':                                                 /* NYX mode */
+
+        if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+        fsrv->nyx_mode = 1;
+        fsrv->nyx_parent = true;
+        fsrv->nyx_standalone = true;
+
+        break;
+#else
+      case 'X':
+        FATAL("Nyx mode is only availabe on linux...");
+        break;
+#endif
+
       case 'H':                                                /* Hang Mode */
 
         /* Minimizes a testcase to the minimum that still times out */
@@ -1068,7 +1086,21 @@ int main(int argc, char **argv_orig, char **envp) {
 
   set_up_environment(fsrv, argv);
 
+#ifdef __linux__
+  if (!fsrv->nyx_mode) {
+
+    fsrv->target_path = find_binary(argv[optind]);
+
+  } else {
+
+    fsrv->target_path = ck_strdup(argv[optind]);
+
+  }
+
+#else
   fsrv->target_path = find_binary(argv[optind]);
+#endif
+
   fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
   detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
   signal(SIGALRM, kill_child);
@@ -1092,6 +1124,26 @@ int main(int argc, char **argv_orig, char **envp) {
     use_argv =
         get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
 
+#ifdef __linux__
+
+  } else if (fsrv->nyx_mode) {
+
+    fsrv->nyx_id = 0;
+
+    u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+    fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+    if (fsrv->nyx_handlers == NULL) {
+
+      FATAL("failed to initialize libnyx.so...");
+
+    }
+
+    fsrv->nyx_use_tmp_workdir = true;
+    fsrv->nyx_bind_cpu_id = 0;
+
+    use_argv = argv + optind;
+#endif
+
   } else {
 
     use_argv = argv + optind;
@@ -1161,7 +1213,12 @@ int main(int argc, char **argv_orig, char **envp) {
   fsrv->shmem_fuzz = map + sizeof(u32);
 
   read_initial_file();
+
+#ifdef __linux__
+  if (!fsrv->nyx_mode) { (void)check_binary_signatures(fsrv->target_path); }
+#else
   (void)check_binary_signatures(fsrv->target_path);
+#endif
 
   if (!fsrv->qemu_mode && !unicorn_mode) {