about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2022-01-11 12:20:35 +0100
committerGitHub <noreply@github.com>2022-01-11 12:20:35 +0100
commit10dae419d6e3ebc38f53840c5abfe98e9c901217 (patch)
tree352576e19c8a504c40ea58dbb141056762901a69 /src
parent74a8f145e09d0361d8f576eb3f2e8881b6116f18 (diff)
parentd2715336a54635bb6e617a2e739c0ad5fe51d28d (diff)
downloadafl++-10dae419d6e3ebc38f53840c5abfe98e9c901217.tar.gz
Merge pull request #1236 from AFLplusplus/dev
push to stable
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c2
-rw-r--r--src/afl-as.c2
-rw-r--r--src/afl-cc.c22
-rw-r--r--src/afl-common.c7
-rw-r--r--src/afl-forkserver.c172
-rw-r--r--src/afl-fuzz-bitmap.c2
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-extras.c2
-rw-r--r--src/afl-fuzz-init.c51
-rw-r--r--src/afl-fuzz-mutators.c2
-rw-r--r--src/afl-fuzz-one.c103
-rw-r--r--src/afl-fuzz-python.c2
-rw-r--r--src/afl-fuzz-queue.c2
-rw-r--r--src/afl-fuzz-redqueen.c2
-rw-r--r--src/afl-fuzz-run.c2
-rw-r--r--src/afl-fuzz-state.c2
-rw-r--r--src/afl-fuzz-stats.c30
-rw-r--r--src/afl-fuzz.c176
-rw-r--r--src/afl-gotcpu.c2
-rw-r--r--src/afl-ld-lto.c2
-rw-r--r--src/afl-sharedmem.c2
-rw-r--r--src/afl-showmap.c13
-rw-r--r--src/afl-tmin.c2
23 files changed, 544 insertions, 60 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 86278c31..fc868603 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-as.c b/src/afl-as.c
index b644b82a..1edc8cca 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 442cf265..49000877 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -5,7 +5,7 @@
    Written by Michal Zalewski, Laszlo Szekeres and Marc Heuse
 
    Copyright 2015, 2016 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -556,7 +556,16 @@ static void edit_params(u32 argc, char **argv, char **envp) {
     if (lto_mode && !have_c) {
 
       u8 *ld_path = NULL;
-      if (getenv("AFL_REAL_LD")) { ld_path = strdup(getenv("AFL_REAL_LD")); }
+      if (getenv("AFL_REAL_LD")) {
+
+        ld_path = strdup(getenv("AFL_REAL_LD"));
+
+      } else {
+
+        ld_path = strdup(AFL_REAL_LD);
+
+      }
+
       if (!ld_path || !*ld_path) { ld_path = strdup("ld.lld"); }
       if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
 #if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
@@ -720,10 +729,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     }
 
-    if (!strcmp(cur, "-z")) {
+    if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
 
       u8 *param = *(argv + 1);
-      if (!strcmp(param, "defs")) {
+      if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
 
         skip_next = 1;
         continue;
@@ -867,7 +876,10 @@ static void edit_params(u32 argc, char **argv, char **envp) {
 
     cc_params[cc_par_cnt++] = "-fsanitize=leak";
     cc_params[cc_par_cnt++] = "-includesanitizer/lsan_interface.h";
-    cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()=__lsan_do_leak_check()";
+    cc_params[cc_par_cnt++] = "-D__AFL_LEAK_CHECK()={if(__lsan_do_recoverable_leak_check() > 0) _exit(23); }";
+    cc_params[cc_par_cnt++] = "-D__AFL_LSAN_OFF()=__lsan_disable();";
+    cc_params[cc_par_cnt++] = "-D__AFL_LSAN_ON()=__lsan_enable();";
+
 
   }
 
diff --git a/src/afl-common.c b/src/afl-common.c
index 6c2d0753..7ba3bb74 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -38,13 +38,10 @@
 #include "common.h"
 
 /* Detect @@ in args. */
-#ifndef __glibc__
-  #include <unistd.h>
-#endif
+#include <unistd.h>
 #include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <unistd.h>
 #include <fcntl.h>
 
 u8  be_quiet = 0;
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index b871ea8c..eebbb7c8 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -13,7 +13,7 @@
 
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -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,82 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
   s32   rlen;
   char *ignore_autodict = getenv("AFL_NO_AUTODICT");
 
+#ifdef __linux__
+  if (unlikely(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 ..."); }
+
+    u32 tmp_map_size =
+        fsrv->nyx_handlers->nyx_get_bitmap_buffer_size(fsrv->nyx_runner);
+    fsrv->real_map_size = fsrv->map_size;
+    fsrv->map_size = (((tmp_map_size + 63) >> 6) << 6);
+    if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_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 +1172,10 @@ 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 +1192,16 @@ 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 (unlikely(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,13 +1315,80 @@ 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. */
 
-  memset(fsrv->trace_bits, 0, fsrv->map_size);
+#ifdef __linux__
+  if (!fsrv->nyx_mode) {
+
+    memset(fsrv->trace_bits, 0, fsrv->map_size);
+    MEM_BARRIER();
+
+  }
 
+#else
+  memset(fsrv->trace_bits, 0, fsrv->map_size);
   MEM_BARRIER();
+#endif
 
   /* we have the fork server (or faux server) up and running
   First, tell it if the previous run timed out. */
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 7a236005..8d044959 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 28a3ae3f..ce8f1a83 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -11,7 +11,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 0f0fe331..535ffdc3 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index e4b83fa5..5449460e 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -393,15 +393,14 @@ void bind_to_free_cpu(afl_state_t *afl) {
         "For this platform we do not have free CPU binding code yet. If possible, please supply a PR to https://github.com/AFLplusplus/AFLplusplus"
   #endif
 
-  size_t cpu_start = 0;
+  #if !defined(__aarch64__) && !defined(__arm__) && !defined(__arm64__)
 
-  #if !defined(__ANDROID__)
-
-  for (i = cpu_start; i < afl->cpu_core_count; i++) {
+  for (i = 0; i < afl->cpu_core_count; i++) {
 
   #else
 
-  /* for some reason Android goes backwards */
+  /* many ARM devices have performance and efficiency cores, the slower
+     efficiency cores seem to always come first */
 
   for (i = afl->cpu_core_count - 1; i > -1; i--) {
 
@@ -413,13 +412,15 @@ void bind_to_free_cpu(afl_state_t *afl) {
 
     if (bind_cpu(afl, i)) {
 
+  #ifdef __linux__
+      if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = i; }
+  #endif
       /* Success :) */
       break;
 
     }
 
     WARNF("setaffinity failed to CPU %d, trying next CPU", i);
-    cpu_start++;
 
   }
 
@@ -1092,6 +1093,14 @@ 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:
@@ -2445,6 +2454,9 @@ 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;
 
@@ -2582,6 +2594,28 @@ 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) {
 
@@ -2721,6 +2755,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-mutators.c b/src/afl-fuzz-mutators.c
index e0dfd6b0..51a43dbd 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -10,7 +10,7 @@
                         Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index 426a6507..26a01948 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -2002,7 +2002,7 @@ havoc_stage:
   /* We essentially just do several thousand runs (depending on perf_score)
      where we take the input file and make random stacked tweaks. */
 
-#define MAX_HAVOC_ENTRY 59                                      /* 55 to 60 */
+#define MAX_HAVOC_ENTRY 64
 #define MUTATE_ASCII_DICT 64
 
   u32 r_max, r;
@@ -2506,12 +2506,101 @@ havoc_stage:
 
         }
 
-        // increase from 4 up to 8?
-        case 52 ... MAX_HAVOC_ENTRY: {
+        case 52: {
 
-          /* Delete bytes. We're making this a bit more likely
-             than insertion (the next option) in hopes of keeping
-             files reasonably small. */
+          /* Increase byte by 1. */
+
+#ifdef INTROSPECTION
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ADDBYTE_");
+          strcat(afl->mutation, afl->m_tmp);
+#endif
+          out_buf[rand_below(afl, temp_len)]++;
+          break;
+
+        }
+
+        case 53: {
+
+          /* Decrease byte by 1. */
+
+#ifdef INTROSPECTION
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SUBBYTE_");
+          strcat(afl->mutation, afl->m_tmp);
+#endif
+          out_buf[rand_below(afl, temp_len)]++;
+          break;
+
+        }
+
+        case 54: {
+
+          /* Flip byte. */
+
+#ifdef INTROSPECTION
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP8_");
+          strcat(afl->mutation, afl->m_tmp);
+#endif
+          out_buf[rand_below(afl, temp_len)] ^= 0xff;
+          break;
+
+        }
+
+        case 55 ... 56: {
+
+          if (temp_len < 4) { break; }
+
+          /* Switch bytes. */
+
+          u32 to_end, switch_to, switch_len, switch_from;
+          switch_from = rand_below(afl, temp_len);
+          do {
+
+            switch_to = rand_below(afl, temp_len);
+
+          } while (switch_from == switch_to);
+
+          if (switch_from < switch_to) {
+
+            switch_len = switch_to - switch_from;
+            to_end = temp_len - switch_to;
+
+          } else {
+
+            switch_len = switch_from - switch_to;
+            to_end = temp_len - switch_from;
+
+          }
+
+          switch_len = choose_block_len(afl, MIN(switch_len, to_end));
+
+#ifdef INTROSPECTION
+          snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SWITCH-%s-%u-%u-%u",
+                   "switch", switch_from, switch_to, switch_len);
+          strcat(afl->mutation, afl->m_tmp);
+#endif
+          u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), switch_len);
+          if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+          /* Backup */
+
+          memcpy(new_buf, out_buf + switch_from, switch_len);
+
+          /* Switch 1 */
+
+          memcpy(out_buf + switch_from, out_buf + switch_to, switch_len);
+
+          /* Switch 2 */
+
+          memcpy(out_buf + switch_to, new_buf, switch_len);
+
+          break;
+
+        }
+
+        // MAX_HAVOC_ENTRY = 64
+        case 57 ... MAX_HAVOC_ENTRY: {
+
+          /* Delete bytes. */
 
           if (temp_len < 2) { break; }
 
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 6484768b..65501c8c 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index 2d76e4d2..9ca89944 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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:
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index e363dffd..1e4b1b3c 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -11,7 +11,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index d730876a..eaa82b19 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -10,7 +10,7 @@
                         Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 737a49a7..69ffa8cf 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 289f7e09..1170bdb8 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -679,11 +679,29 @@ 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
 
   }
 
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index f59bb47c..1030dfdf 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -37,6 +37,7 @@
 
 #ifdef __APPLE__
   #include <sys/qos.h>
+  #include <pthread/qos.h>
 #endif
 
 #ifdef PROFILING
@@ -104,7 +105,7 @@ static void usage(u8 *argv0, int more_help) {
       "  -p schedule   - power schedules compute a seed's performance score:\n"
       "                  fast(default), explore, exploit, seek, rare, mmopt, "
       "coe, lin\n"
-      "                  quad -- see docs/power_schedules.md\n"
+      "                  quad -- see docs/FAQ.md for more information\n"
       "  -f file       - location read by the fuzzed program (default: stdin "
       "or @@)\n"
       "  -t msec       - timeout for each run (auto-scaled, default %u ms). "
@@ -123,6 +124,10 @@ static void usage(u8 *argv0, int more_help) {
       "  -W            - use qemu-based instrumentation with Wine (Wine "
       "mode)\n"
 #endif
+#if defined(__linux__)
+      "  -X            - use VM fuzzing (NYX mode - standalone mode)\n"
+      "  -Y            - use VM fuzzing (NYX mode - multiple instances mode)\n"
+#endif
       "\n"
 
       "Mutator settings:\n"
@@ -384,6 +389,60 @@ 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) {
@@ -440,7 +499,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) {
@@ -844,6 +903,29 @@ 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 -Y 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__)
@@ -1184,6 +1266,16 @@ 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) {
 
@@ -1226,6 +1318,56 @@ 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(
+              "for Nyx -Y mode, the Main (-M) parameter has to be set to 0 (-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(
+              "for Nyx -Y mode, the Secondary (-S) parameter has to be a "
+              "numeric value and >= 1 (e.g. -S 1)");
+
+        }
+
+        afl->fsrv.nyx_id = nyx_id;
+
+      }
+
+    }
+
+  }
+
+  #endif
+
   if (afl->sync_id) {
 
     if (strlen(afl->sync_id) > 24) {
@@ -1449,8 +1591,28 @@ 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], "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,6 +2096,14 @@ 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-gotcpu.c b/src/afl-gotcpu.c
index f8466680..539206ce 100644
--- a/src/afl-gotcpu.c
+++ b/src/afl-gotcpu.c
@@ -9,7 +9,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
index 1dcdb176..9b58125f 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -9,7 +9,7 @@
                 Andrea Fioraldi <andreafioraldi@gmail.com>
                 Dominik Maier <domenukk@gmail.com>
 
-  Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+  Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index c1d4ff03..8d58bb3e 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -11,7 +11,7 @@
                         Andrea Fioraldi <andreafioraldi@gmail.com>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
diff --git a/src/afl-showmap.c b/src/afl-showmap.c
index 115f9f2a..3fdbe8fe 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -12,7 +12,7 @@
                         Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.
@@ -105,15 +105,8 @@ static sharedmem_t *     shm_fuzz;
 
 static const u8 count_class_human[256] = {
 
-    [0] = 0,
-    [1] = 1,
-    [2] = 2,
-    [3] = 3,
-    [4] = 4,
-    [8] = 5,
-    [16] = 6,
-    [32] = 7,
-    [128] = 8
+    [0] = 0, [1] = 1,  [2] = 2,  [3] = 3,  [4] = 4,
+    [8] = 5, [16] = 6, [32] = 7, [128] = 8
 
 };
 
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index b5b015ce..1bf4af38 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -12,7 +12,7 @@
                         Dominik Maier <mail@dmnk.co>
 
    Copyright 2016, 2017 Google Inc. All rights reserved.
-   Copyright 2019-2020 AFLplusplus Project. All rights reserved.
+   Copyright 2019-2022 AFLplusplus Project. 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.