about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2021-12-28 17:19:34 +0100
committerGitHub <noreply@github.com>2021-12-28 17:19:34 +0100
commit83bf876255f854555d8b98560112c094ed8d693e (patch)
tree25161d8b9c2d45f4de222a30fea63b8359248acb
parentf9d4dcdd85fcbc29672a58801fea0f388691ec5f (diff)
parent41291d8c72f91f5c4544de384e8dc5c2817364f0 (diff)
downloadafl++-83bf876255f854555d8b98560112c094ed8d693e.tar.gz
Merge pull request #1233 from nyx-fuzz/dev
add Nyx mode
-rw-r--r--.gitmodules9
-rw-r--r--GNUmakefile3
-rw-r--r--include/forkserver.h45
m---------nyx_mode/QEMU-Nyx0
-rw-r--r--nyx_mode/build_nyx_support.sh69
m---------nyx_mode/libnyx0
m---------nyx_mode/packer0
-rw-r--r--src/afl-forkserver.c140
-rw-r--r--src/afl-fuzz-init.c32
-rw-r--r--src/afl-fuzz-stats.c23
-rw-r--r--src/afl-fuzz.c157
11 files changed, 468 insertions, 10 deletions
diff --git a/.gitmodules b/.gitmodules
index 6569c0b1..8ba1c39d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -19,3 +19,12 @@
 [submodule "coresight_mode/coresight-trace"]
 	path = coresight_mode/coresight-trace
 	url = https://github.com/RICSecLab/coresight-trace.git
+[submodule "nyx_mode/libnyx"]
+	path = nyx_mode/libnyx
+	url = https://github.com/nyx-fuzz/libnyx.git
+[submodule "nyx_mode/QEMU-Nyx"]
+	path = nyx_mode/QEMU-Nyx
+	url = https://github.com/nyx-fuzz/qemu-nyx.git
+[submodule "nyx_mode/packer"]
+	path = nyx_mode/packer
+	url = https://github.com/nyx-fuzz/packer.git
diff --git a/GNUmakefile b/GNUmakefile
index a2c80261..fc1d2768 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -346,7 +346,7 @@ help:
 	@echo "HELP --- the following make targets exist:"
 	@echo "=========================================="
 	@echo "all: the main afl++ binaries and llvm/gcc instrumentation"
-	@echo "binary-only: everything for binary-only fuzzing: frida_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
+	@echo "binary-only: everything for binary-only fuzzing: frida_mode, nyx_mode, qemu_mode, frida_mode, unicorn_mode, coresight_mode, libdislocator, libtokencap"
 	@echo "source-only: everything for source code fuzzing: libdislocator, libtokencap"
 	@echo "distrib: everything (for both binary-only and source code fuzzing)"
 	@echo "man: creates simple man pages from the help option of the programs"
@@ -636,6 +636,7 @@ ifeq "$(ARCH)" "aarch64"
 endif
 	-cd qemu_mode && sh ./build_qemu_support.sh
 	-cd unicorn_mode && unset CFLAGS && sh ./build_unicorn_support.sh
+	-cd nyx_mode && sh ./build_nyx_support.sh
 endif
 
 .PHONY: source-only
diff --git a/include/forkserver.h b/include/forkserver.h
index 464f208d..227f75c1 100644
--- a/include/forkserver.h
+++ b/include/forkserver.h
@@ -33,6 +33,40 @@
 
 #include "types.h"
 
+#ifdef __linux__
+/**
+ * Nyx related typedefs taken from libnyx.h
+ */
+
+typedef enum NyxReturnValue {
+  Normal,
+  Crash,
+  Asan,
+  Timout,
+  InvalidWriteToPayload,
+  Error,
+  IoError,
+  Abort,
+} NyxReturnValue;
+
+typedef struct{
+  void* (*nyx_new)(const char *sharedir,
+            const char *workdir,
+            uint32_t worker_id,
+            uint32_t cpu_id,
+            bool create_snapshot);
+  void (*nyx_shutdown)(void *qemu_process);
+  void (*nyx_option_set_reload_mode)(void *qemu_process, bool enable);
+  void (*nyx_option_set_timeout)(void *qemu_process, uint8_t timeout_sec, uint32_t timeout_usec);
+  void (*nyx_option_apply)(void *qemu_process);
+  void (*nyx_set_afl_input)(void *qemu_process, uint8_t *buffer, uint32_t size);
+  enum NyxReturnValue (*nyx_exec)(void *qemu_process);
+  uint8_t* (*nyx_get_bitmap_buffer)(void *qemu_process);
+  size_t (*nyx_get_bitmap_buffer_size)(void *qemu_process);
+} nyx_plugin_handler_t;
+
+#endif
+
 typedef struct afl_forkserver {
 
   /* a program that includes afl-forkserver needs to define these */
@@ -121,6 +155,17 @@ typedef struct afl_forkserver {
 
   u8 kill_signal;
 
+#ifdef __linux__
+  nyx_plugin_handler_t* nyx_handlers;
+  char *out_dir_path;                   /* path to the output directory     */
+  u8 nyx_mode;                          /* if running in nyx mode or not    */
+  bool nyx_parent;                      /* create initial snapshot          */
+  bool nyx_standalone;                  /* don't serialize the snapshot     */
+  void* nyx_runner;                     /* nyx runner object                */
+  u32 nyx_id;                           /* nyx runner id (0 -> master)      */ 
+  u32 nyx_bind_cpu_id;                  /* nyx runner cpu id                */ 
+#endif
+
 } afl_forkserver_t;
 
 typedef enum fsrv_run_result {
diff --git a/nyx_mode/QEMU-Nyx b/nyx_mode/QEMU-Nyx
new file mode 160000
+Subproject acc90e462b45fab15bb6b28c064e9f78808cb34
diff --git a/nyx_mode/build_nyx_support.sh b/nyx_mode/build_nyx_support.sh
new file mode 100644
index 00000000..67e38117
--- /dev/null
+++ b/nyx_mode/build_nyx_support.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+set -e
+
+echo "================================================="
+echo "           Nyx build script"
+echo "================================================="
+echo
+
+echo "[*] Performing basic sanity checks..."
+
+if [ ! "`uname -s`" = "Linux" ]; then
+
+  echo "[-] Error: Nyx mode is only available on Linux."
+  exit 0
+
+fi
+
+echo "[*] Making sure all Nyx is checked out"
+
+git status 1>/dev/null 2>/dev/null
+if [ $? -eq 0 ]; then
+  git submodule init || exit 1
+  echo "[*] initializing QEMU-Nyx submodule"
+  git submodule update ./QEMU-Nyx 2>/dev/null # ignore errors
+  echo "[*] initializing packer submodule"
+  git submodule update ./packer 2>/dev/null # ignore errors
+  echo "[*] initializing libnyx submodule"
+  git submodule update ./libnyx 2>/dev/null # ignore errors
+
+else
+  echo "[ ] not a git repo..."
+  exit 1
+fi
+
+test -d QEMU-Nyx || { echo "[-] Not checked out, please install git or check your internet connection." ; exit 1 ; }
+test -d packer || { echo "[-] Not checked out, please install git or check your internet connection." ; exit 1 ; }
+test -d libnyx || { echo "[-] Not checked out, please install git or check your internet connection." ; exit 1 ; }
+
+echo "[*] checking packer init.cpio.gz ..."
+if [ ! -f "packer/linux_initramfs/init.cpio.gz" ]; then
+    cd packer/linux_initramfs/
+    sh pack.sh
+    cd ../../
+fi
+
+echo "[*] Checking libnyx ..."
+if [ ! -f "libnyx/libnyx/target/release/liblibnyx.a" ]; then
+    cd libnyx/libnyx
+    cargo build --release
+    cd ../../
+fi
+
+echo "[*] Checking QEMU-Nyx ..."
+if [ ! -f "QEMU-Nyx/x86_64-softmmu/qemu-system-x86_64" ]; then
+    cd QEMU-Nyx/
+    ./compile_qemu_nyx.sh
+    cd ..
+fi
+
+echo "[*] Checking libnyx.so ..."
+if [ -f "libnyx/libnyx/target/release/liblibnyx.so" ]; then
+  cp libnyx/libnyx/target/release/liblibnyx.so libnyx.so
+else
+  echo "[ ] libnyx.so not found..."
+  exit 1
+fi
+echo "[+] All done for nyx_mode, enjoy!"
+
+exit 0
\ No newline at end of file
diff --git a/nyx_mode/libnyx b/nyx_mode/libnyx
new file mode 160000
+Subproject ecbcb2d7234fef0b5e1db8ca6019e6137ee0582
diff --git a/nyx_mode/packer b/nyx_mode/packer
new file mode 160000
+Subproject 87837335d6a9834516aacf4121cbe0e2b969212
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index b871ea8c..6604de3a 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -71,6 +71,17 @@ static void fsrv_exec_child(afl_forkserver_t *fsrv, char **argv) {
 
 void afl_fsrv_init(afl_forkserver_t *fsrv) {
 
+#ifdef __linux__
+  fsrv->nyx_handlers = NULL;
+  fsrv->out_dir_path = NULL;
+  fsrv->nyx_mode = 0;
+  fsrv->nyx_parent = false;
+  fsrv->nyx_standalone = false;
+  fsrv->nyx_runner = NULL;
+  fsrv->nyx_id = 0xFFFFFFFF;
+  fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
+#endif
+
   // this structure needs default so we initialize it if this was not done
   // already
   fsrv->out_fd = -1;
@@ -375,6 +386,72 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
   s32   rlen;
   char *ignore_autodict = getenv("AFL_NO_AUTODICT");
 
+#ifdef __linux__
+  if (fsrv->nyx_mode) {
+
+    if(fsrv->nyx_runner != NULL){
+      return;
+    }
+
+    if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
+
+    if(fsrv->out_dir_path == NULL){
+        FATAL("Nyx workdir path not found...");
+    }
+
+    char *x = alloc_printf("%s/workdir", fsrv->out_dir_path);
+
+    if(fsrv->nyx_id == 0xFFFFFFFF){
+        FATAL("Nyx ID is not set..."); 
+    }
+
+    if(fsrv->nyx_bind_cpu_id == 0xFFFFFFFF){
+      FATAL("Nyx CPU ID is not set..."); 
+    }
+
+    if (fsrv->nyx_parent){
+      fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(fsrv->target_path, x, fsrv->nyx_id, fsrv->nyx_bind_cpu_id, !fsrv->nyx_standalone);
+    }
+    else{
+      fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(fsrv->target_path, x, fsrv->nyx_id, fsrv->nyx_bind_cpu_id, true);
+    }
+
+    if(fsrv->nyx_runner == NULL){
+      FATAL("Something went wrong ...");
+    }
+
+    fsrv->map_size = fsrv->nyx_handlers->nyx_get_bitmap_buffer_size(fsrv->nyx_runner);;
+    fsrv->real_map_size = fsrv->map_size;
+
+    fsrv->trace_bits = fsrv->nyx_handlers->nyx_get_bitmap_buffer(fsrv->nyx_runner);
+
+    fsrv->nyx_handlers->nyx_option_set_reload_mode(fsrv->nyx_runner, getenv("NYX_DISABLE_SNAPSHOT_MODE") == NULL);
+    fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+
+    fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, 2, 0);
+    fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+
+    /* dry run */
+    fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, "INIT", 4);
+    switch(fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)){
+      case Abort:
+        fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+        FATAL("Error: Nyx abort occured...");
+        break;
+      case IoError:
+        FATAL("Error: QEMU-Nyx has died...");
+        break;
+      case Error:
+        fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+        FATAL("Error: Nyx runtime error has occured...");
+        break;
+      default:
+        break;
+    }
+    return;
+  }
+#endif
+
   if (!be_quiet) { ACTF("Spinning up the fork server..."); }
 
 #ifdef AFL_PERSISTENT_RECORD
@@ -1085,6 +1162,11 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
   fsrv->fsrv_pid = -1;
   fsrv->child_pid = -1;
 
+#ifdef __linux__
+  if(fsrv->nyx_mode){
+    fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+  }
+#endif
 }
 
 /* Get the map size from the target forkserver */
@@ -1101,6 +1183,12 @@ u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv,
 
 void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) {
 
+#ifdef __linux__
+  if(fsrv->nyx_mode){
+    fsrv->nyx_handlers->nyx_set_afl_input(fsrv->nyx_runner, buf, len);
+    return;
+  }
+#endif
 #ifdef AFL_PERSISTENT_RECORD
   if (unlikely(fsrv->persistent_record)) {
 
@@ -1214,12 +1302,62 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
   u32 exec_ms;
   u32 write_value = fsrv->last_run_timed_out;
 
+#ifdef __linux__
+  if(fsrv->nyx_mode){
+
+    static uint32_t last_timeout_value = 0;
+
+    if (last_timeout_value != timeout){
+      fsrv->nyx_handlers->nyx_option_set_timeout(fsrv->nyx_runner, timeout/1000, (timeout%1000) * 1000);
+      fsrv->nyx_handlers->nyx_option_apply(fsrv->nyx_runner);
+      last_timeout_value = timeout;
+    }
+
+    enum NyxReturnValue ret_val = fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner);
+
+    fsrv->total_execs++;
+
+    switch(ret_val){
+      case Normal:
+        return FSRV_RUN_OK;
+      case Crash:
+      case Asan:
+        return FSRV_RUN_CRASH;
+      case Timout:
+        return FSRV_RUN_TMOUT;
+      case InvalidWriteToPayload:
+        /* ??? */
+        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){
+          return 0;
+        }
+        else{
+          FATAL("Error: QEMU-Nyx has died...");
+        }
+        break;
+      case Error:
+        FATAL("Error: Nyx runtime error has occured...");
+        break;
+    }
+    return FSRV_RUN_OK;
+  }                           
+#endif
   /* After this memset, fsrv->trace_bits[] are effectively volatile, so we
      must prevent any earlier operations from venturing into that
      territory. */
 
+#ifdef __linux__
+  if(!fsrv->nyx_mode){
+    memset(fsrv->trace_bits, 0, fsrv->map_size);
+  }
+#else
   memset(fsrv->trace_bits, 0, fsrv->map_size);
-
+#endif
   MEM_BARRIER();
 
   /* we have the fork server (or faux server) up and running
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 7a8bd674..b6de3712 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -411,7 +411,11 @@ void bind_to_free_cpu(afl_state_t *afl) {
     OKF("Found a free CPU core, try binding to #%u.", i);
 
     if (bind_cpu(afl, i)) {
-
+#ifdef __linux__
+      if(afl->fsrv.nyx_mode){
+        afl->fsrv.nyx_bind_cpu_id = i;
+      }
+#endif
       /* Success :) */
       break;
 
@@ -1090,6 +1094,11 @@ void perform_dry_run(afl_state_t *afl) {
         FATAL("Unable to execute target application ('%s')", afl->argv[0]);
 
       case FSRV_RUN_NOINST:
+#ifdef __linux__
+        if(afl->fsrv.nyx_mode && afl->fsrv.nyx_runner != NULL){
+          afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
+        }
+#endif
         FATAL("No instrumentation detected");
 
       case FSRV_RUN_NOBITS:
@@ -2443,6 +2452,11 @@ void fix_up_sync(afl_state_t *afl) {
 
   x = alloc_printf("%s/%s", afl->out_dir, afl->sync_id);
 
+#ifdef __linux__
+  if(afl->fsrv.nyx_mode){
+    afl->fsrv.out_dir_path = afl->out_dir;
+  }
+#endif
   afl->sync_dir = afl->out_dir;
   afl->out_dir = x;
 
@@ -2580,6 +2594,19 @@ void check_binary(afl_state_t *afl, u8 *fname) {
   if (strchr(fname, '/') || !(env_path = getenv("PATH"))) {
 
     afl->fsrv.target_path = ck_strdup(fname);
+#ifdef __linux__
+    if(afl->fsrv.nyx_mode){
+      /* check if target_path is a nyx sharedir */
+      if (stat(afl->fsrv.target_path, &st) || S_ISDIR(st.st_mode)){
+        char* tmp = alloc_printf("%s/config.ron", afl->fsrv.target_path);
+        if (stat(tmp, &st) || S_ISREG(st.st_mode)){
+          free(tmp);
+          return;
+        }
+      }
+      FATAL("Directory '%s' not found or is not a nyx share directory", afl->fsrv.target_path);
+    }
+#endif
     if (stat(afl->fsrv.target_path, &st) || !S_ISREG(st.st_mode) ||
         !(st.st_mode & 0111) || (f_len = st.st_size) < 4) {
 
@@ -2719,6 +2746,9 @@ void check_binary(afl_state_t *afl, u8 *fname) {
 #endif                                                       /* ^!__APPLE__ */
 
   if (!afl->fsrv.qemu_mode && !afl->fsrv.frida_mode && !afl->unicorn_mode &&
+#ifdef __linux__
+      !afl->fsrv.nyx_mode &&
+#endif
       !afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
       !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
 
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 289f7e09..5f035762 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -679,12 +679,25 @@ void show_stats(afl_state_t *afl) {
     banner_pad = (79 - banner_len) / 2;
     memset(banner, ' ', banner_pad);
 
-    sprintf(banner + banner_pad,
-            "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
-            afl->crash_mode ? cPIN "peruvian were-rabbit"
-                            : cYEL "american fuzzy lop",
-            si, afl->use_banner, afl->power_name);
+#ifdef __linux__
+    if(afl->fsrv.nyx_mode){
+      sprintf(banner + banner_pad,
+              "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+              afl->crash_mode ? cPIN "peruvian were-rabbit"
+                              : cYEL "american fuzzy lop",
+              si, afl->use_banner, afl->power_name);
+    }
+    else{
+#endif
+      sprintf(banner + banner_pad,
+              "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+              afl->crash_mode ? cPIN "peruvian were-rabbit"
+                              : cYEL "american fuzzy lop",
+              si, afl->use_banner, afl->power_name);
 
+#ifdef __linux__
+    }
+#endif
   }
 
   SAYF("\n%s\n", banner);
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index f52637f5..7ab2c60e 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -124,6 +124,8 @@ static void usage(u8 *argv0, int more_help) {
       "  -W            - use qemu-based instrumentation with Wine (Wine "
       "mode)\n"
 #endif
+      "  -X            - use VM fuzzing (NYX mode)\n"
+      "  -Y            - use VM fuzzing (NYX mode - Multiprocessing)\n"
       "\n"
 
       "Mutator settings:\n"
@@ -385,6 +387,75 @@ 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_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;
+    }
+    
+    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) {
@@ -441,7 +512,7 @@ int main(int argc, char **argv_orig, char **envp) {
 
   while ((opt = getopt(
               argc, argv,
-              "+Ab:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) >
+              "+Ab:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOXYo:p:RQs:S:t:T:UV:Wx:Z")) >
          0) {
 
     switch (opt) {
@@ -845,6 +916,36 @@ int main(int argc, char **argv_orig, char **envp) {
         afl->use_banner = optarg;
         break;
 
+#ifdef __linux__
+      case 'X':                                               /* NYX mode */
+
+        if (afl->fsrv.nyx_mode) {
+          FATAL("Multiple -X options not supported");
+
+        }
+
+        afl->fsrv.nyx_parent = true;
+        afl->fsrv.nyx_standalone = true;
+        afl->fsrv.nyx_mode = 1;
+        afl->fsrv.nyx_id = 0;
+
+        break;
+
+      case 'Y':                                               /* NYX distributed mode */
+        if (afl->fsrv.nyx_mode) {
+
+          FATAL("Multiple -X options not supported");
+
+        }
+        afl->fsrv.nyx_mode = 1;
+
+        break;
+#else
+      case 'X':
+      case 'Y':
+        FATAL("Nyx mode is only availabe on linux...");
+        break;
+#endif
       case 'A':                                           /* CoreSight mode */
 
   #if !defined(__aarch64__) || !defined(__linux__)
@@ -1185,6 +1286,13 @@ int main(int argc, char **argv_orig, char **envp) {
   OKF("NOTE: This is v3.x which changes defaults and behaviours - see "
       "README.md");
 
+#ifdef __linux__
+  if (afl->fsrv.nyx_mode){
+    OKF("afl++ Nyx mode is enabled (developed and mainted by Sergej Schumilo)");
+    OKF("Nyx is open source, get it at "
+      "https://github.com/Nyx-Fuzz");
+  }
+#endif
   if (afl->sync_id && afl->is_main_node &&
       afl->afl_env.afl_custom_mutator_only) {
 
@@ -1227,6 +1335,33 @@ int main(int argc, char **argv_orig, char **envp) {
 
   }
 
+#ifdef __linux__
+  if (afl->fsrv.nyx_mode) {
+
+    if (afl->fsrv.nyx_standalone && strncmp(afl->sync_id, "default", strlen("default")) != 0){
+      FATAL("distributed fuzzing is not supported in this Nyx mode (use -Y instead)");
+    }
+
+    if (!afl->fsrv.nyx_standalone){
+      if (afl->is_main_node){
+        if(strncmp("0", afl->sync_id, strlen("0") != 0)){
+          FATAL("afl->sync_id has to be 0 in Nyx mode (-M 0)");
+        }
+        afl->fsrv.nyx_id = 0;
+      }
+
+      if (afl->is_secondary_node){
+        long nyx_id = strtol(afl->sync_id, NULL, 10);
+
+        if (nyx_id == 0 || nyx_id == LONG_MAX){
+          FATAL("afl->sync_id has to be numberic and >= 1 (-S id)");
+        }
+        afl->fsrv.nyx_id = nyx_id;
+      }
+    }
+  }
+#endif
+
   if (afl->sync_id) {
 
     if (strlen(afl->sync_id) > 24) {
@@ -1450,8 +1585,22 @@ int main(int argc, char **argv_orig, char **envp) {
 
   afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
 
+#ifdef __linux__
+  if (!afl->fsrv.nyx_mode){
+    check_crash_handling();
+    check_cpu_governor(afl);
+  }
+  else{
+    u8* libnyx_binary = find_afl_binary(argv[0], "nyx_mode/libnyx.so");    
+    afl->fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+    if(afl->fsrv.nyx_handlers == NULL){
+      FATAL("failed to initialize libnyx.so...");
+    }
+  }
+#else
   check_crash_handling();
   check_cpu_governor(afl);
+#endif
 
   if (getenv("LD_PRELOAD")) {
 
@@ -1934,7 +2083,11 @@ int main(int argc, char **argv_orig, char **envp) {
     if (!afl->queue_buf[entry]->disabled) { ++valid_seeds; }
 
   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!");
 
   }