aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Shvedov <60114847+a-shvedov@users.noreply.github.com>2024-05-30 10:43:01 +0300
committerGitHub <noreply@github.com>2024-05-30 10:43:01 +0300
commitf8a5f1cd9ea907654f42fa06ce6b6bfd4b8c1b13 (patch)
tree7aec2a095a30ed609ce96f85ec3c4e0a8b8eb74c /src
parent629edb1e78d791894ce9ee6d53259f95fe1a29af (diff)
parente7d871c8bf64962a658e447b90a1a3b43aaddc28 (diff)
downloadafl++-f8a5f1cd9ea907654f42fa06ce6b6bfd4b8c1b13.tar.gz
Merge branch 'AFLplusplus:stable' into stable
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c4
-rw-r--r--src/afl-as.c4
-rw-r--r--src/afl-cc.c3712
-rw-r--r--src/afl-common.c117
-rw-r--r--src/afl-forkserver.c601
-rw-r--r--src/afl-fuzz-bitmap.c135
-rw-r--r--src/afl-fuzz-cmplog.c4
-rw-r--r--src/afl-fuzz-extras.c16
-rw-r--r--src/afl-fuzz-init.c321
-rw-r--r--src/afl-fuzz-mutators.c16
-rw-r--r--src/afl-fuzz-one.c1230
-rw-r--r--src/afl-fuzz-python.c34
-rw-r--r--src/afl-fuzz-queue.c89
-rw-r--r--src/afl-fuzz-redqueen.c697
-rw-r--r--src/afl-fuzz-run.c174
-rw-r--r--src/afl-fuzz-skipdet.c403
-rw-r--r--src/afl-fuzz-state.c60
-rw-r--r--src/afl-fuzz-stats.c354
-rw-r--r--src/afl-fuzz-statsd.c2
-rw-r--r--src/afl-fuzz.c444
-rw-r--r--src/afl-gotcpu.c4
-rw-r--r--src/afl-ld-lto.c16
-rw-r--r--src/afl-performance.c345
-rw-r--r--src/afl-sharedmem.c4
-rw-r--r--src/afl-showmap.c34
-rw-r--r--src/afl-tmin.c38
-rw-r--r--src/hashmap.c149
27 files changed, 6433 insertions, 2574 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 5b122741..d089cd08 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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 772e31b3..d4ddb94d 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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 972ac8cd..c872b2eb 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-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -17,6 +17,10 @@
#define AFL_MAIN
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE 1
+#endif
+
#include "common.h"
#include "config.h"
#include "types.h"
@@ -32,7 +36,9 @@
#include <limits.h>
#include <assert.h>
#include <ctype.h>
+#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#if (LLVM_MAJOR - 0 == 0)
#undef LLVM_MAJOR
@@ -47,23 +53,22 @@
#define LLVM_MINOR 0
#endif
-static u8 *obj_path; /* Path to runtime libraries */
-static u8 **cc_params; /* Parameters passed to the real CC */
-static u32 cc_par_cnt = 1; /* Param count, including argv0 */
-static u8 clang_mode; /* Invoked as afl-clang*? */
-static u8 llvm_fullpath[PATH_MAX];
-static u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k, lto_mode;
-static u8 compiler_mode, plusplus_mode, have_instr_env = 0, need_aflpplib = 0;
-static u8 have_gcc, have_llvm, have_gcc_plugin, have_lto, have_instr_list = 0;
-static u8 *lto_flag = AFL_CLANG_FLTO, *argvnull;
-static u8 debug;
-static u8 cwd[4096];
-static u8 cmplog_mode;
-u8 use_stdin; /* dummy */
-static int passthrough;
-// static u8 *march_opt = CFLAGS_OPT;
-
-enum {
+#ifndef MAX_PARAMS_NUM
+ #define MAX_PARAMS_NUM 2048
+#endif
+
+/** Global declarations -----BEGIN----- **/
+
+typedef enum {
+
+ PARAM_MISS, // not matched
+ PARAM_SCAN, // scan only
+ PARAM_KEEP, // kept as-is
+ PARAM_DROP, // ignored
+
+} param_st;
+
+typedef enum {
INSTRUMENT_DEFAULT = 0,
INSTRUMENT_CLASSIC = 1,
@@ -80,7 +85,20 @@ enum {
INSTRUMENT_OPT_CTX_K = 64,
INSTRUMENT_OPT_CODECOV = 128,
-};
+} instrument_mode_id;
+
+typedef enum {
+
+ UNSET = 0,
+ LTO = 1,
+ LLVM = 2,
+ GCC_PLUGIN = 3,
+ GCC = 4,
+ CLANG = 5
+
+} compiler_mode_id;
+
+static u8 cwd[4096];
char instrument_mode_string[18][18] = {
@@ -105,17 +123,6 @@ char instrument_mode_string[18][18] = {
};
-enum {
-
- UNSET = 0,
- LTO = 1,
- LLVM = 2,
- GCC_PLUGIN = 3,
- GCC = 4,
- CLANG = 5
-
-};
-
char compiler_mode_string[7][12] = {
"AUTOSELECT", "LLVM-LTO", "LLVM", "GCC_PLUGIN",
@@ -123,6 +130,18 @@ char compiler_mode_string[7][12] = {
};
+u8 *instrument_mode_2str(instrument_mode_id i) {
+
+ return instrument_mode_string[i];
+
+}
+
+u8 *compiler_mode_2str(compiler_mode_id i) {
+
+ return compiler_mode_string[i];
+
+}
+
u8 *getthecwd() {
if (getcwd(cwd, sizeof(cwd)) == NULL) {
@@ -136,26 +155,237 @@ u8 *getthecwd() {
}
-/* Try to find a specific runtime we need, returns NULL on fail. */
+typedef struct aflcc_state {
+
+ u8 **cc_params; /* Parameters passed to the real CC */
+ u32 cc_par_cnt; /* Param count, including argv0 */
+
+ u8 *argv0; /* Original argv0 (by strdup) */
+ u8 *callname; /* Executable file argv0 indicated */
+
+ u8 debug;
+
+ u8 compiler_mode, plusplus_mode, lto_mode;
+
+ u8 *lto_flag;
+
+ u8 instrument_mode, instrument_opt_mode, ngram_size, ctx_k;
+
+ u8 cmplog_mode;
+
+ u8 have_instr_env, have_gcc, have_clang, have_llvm, have_gcc_plugin, have_lto,
+ have_optimized_pcguard, have_instr_list;
+
+ u8 fortify_set, x_set, bit_mode, preprocessor_only, have_unroll, have_o,
+ have_pic, have_c, shared_linking, partial_linking, non_dash, have_fp,
+ have_flto, have_hidden, have_fortify, have_fcf, have_staticasan,
+ have_rust_asanrt, have_asan, have_msan, have_ubsan, have_lsan, have_tsan,
+ have_cfisan;
+
+ // u8 *march_opt;
+ u8 need_aflpplib;
+ int passthrough;
+
+ u8 use_stdin; /* dummy */
+ u8 *argvnull; /* dummy */
+
+} aflcc_state_t;
+
+void aflcc_state_init(aflcc_state_t *, u8 *argv0);
+
+u8 *find_object(aflcc_state_t *, u8 *obj);
+
+void find_built_deps(aflcc_state_t *);
+
+/* Insert param into the new argv, raise error if MAX_PARAMS_NUM exceeded. */
+static inline void insert_param(aflcc_state_t *aflcc, u8 *param) {
+
+ if (unlikely(aflcc->cc_par_cnt + 1 >= MAX_PARAMS_NUM))
+ FATAL("Too many command line parameters, please increase MAX_PARAMS_NUM.");
+
+ aflcc->cc_params[aflcc->cc_par_cnt++] = param;
+
+}
/*
- in find_object() we look here:
+ Insert a param which contains path to the object file. It uses find_object to
+ get the path based on the name `obj`, and then uses a sprintf like method to
+ format it with `fmt`. If `fmt` is NULL, the inserted arg is same as the path.
+ If `msg` provided, it should be an error msg raised if the path can't be
+ found. `obj` must not be NULL.
+*/
+static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
+ u8 *msg) {
+
+ u8 *_obj_path = find_object(aflcc, obj);
+ if (!_obj_path) {
+
+ if (msg)
+ FATAL("%s", msg);
+ else
+ FATAL("Unable to find '%s'", obj);
+
+ } else {
+
+ if (fmt) {
+
+ u8 *_obj_path_fmt = alloc_printf(fmt, _obj_path);
+ ck_free(_obj_path);
+ aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path_fmt;
+
+ } else {
+
+ aflcc->cc_params[aflcc->cc_par_cnt++] = _obj_path;
+
+ }
+
+ }
+
+}
+
+/* Insert params into the new argv, make clang load the pass. */
+static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
+
+#if LLVM_MAJOR >= 11 /* use new pass manager */
+ #if LLVM_MAJOR < 16
+ insert_param(aflcc, "-fexperimental-new-pass-manager");
+ #endif
+ insert_object(aflcc, pass, "-fpass-plugin=%s", 0);
+#else
+ insert_param(aflcc, "-Xclang");
+ insert_param(aflcc, "-load");
+ insert_param(aflcc, "-Xclang");
+ insert_object(aflcc, pass, 0, 0);
+#endif
+
+}
+
+static inline void debugf_args(int argc, char **argv) {
+
+ DEBUGF("cd '%s';", getthecwd());
+ for (int i = 0; i < argc; i++)
+ SAYF(" '%s'", argv[i]);
+ SAYF("\n");
+ fflush(stdout);
+ fflush(stderr);
+
+}
- 1. if obj_path is already set we look there first
- 2. then we check the $AFL_PATH environment variable location if set
- 3. next we check argv[0] if it has path information and use it
+void compiler_mode_by_callname(aflcc_state_t *);
+void compiler_mode_by_environ(aflcc_state_t *);
+void compiler_mode_by_cmdline(aflcc_state_t *, int argc, char **argv);
+void instrument_mode_by_environ(aflcc_state_t *);
+void mode_final_checkout(aflcc_state_t *, int argc, char **argv);
+void mode_notification(aflcc_state_t *);
+
+void add_real_argv0(aflcc_state_t *);
+
+void add_defs_common(aflcc_state_t *);
+void add_defs_selective_instr(aflcc_state_t *);
+void add_defs_persistent_mode(aflcc_state_t *);
+void add_defs_fortify(aflcc_state_t *, u8);
+void add_defs_lsan_ctrl(aflcc_state_t *);
+
+param_st parse_fsanitize(aflcc_state_t *, u8 *, u8);
+void add_sanitizers(aflcc_state_t *, char **envp);
+void add_optimized_pcguard(aflcc_state_t *);
+void add_native_pcguard(aflcc_state_t *);
+
+void add_assembler(aflcc_state_t *);
+void add_gcc_plugin(aflcc_state_t *);
+
+param_st parse_misc_params(aflcc_state_t *, u8 *, u8);
+void add_misc_params(aflcc_state_t *);
+
+param_st parse_linking_params(aflcc_state_t *, u8 *, u8, u8 *skip_next,
+ char **argv);
+
+void add_lto_linker(aflcc_state_t *);
+void add_lto_passes(aflcc_state_t *);
+void add_runtime(aflcc_state_t *);
+
+/** Global declarations -----END----- **/
+
+/*
+ Init global state struct. We also extract the callname,
+ check debug options and if in C++ mode here.
+*/
+void aflcc_state_init(aflcc_state_t *aflcc, u8 *argv0) {
+
+ // Default NULL/0 is a good start
+ memset(aflcc, 0, sizeof(aflcc_state_t));
+
+ aflcc->cc_params = ck_alloc(MAX_PARAMS_NUM * sizeof(u8 *));
+ aflcc->cc_par_cnt = 1;
+
+ aflcc->lto_flag = AFL_CLANG_FLTO;
+
+ // aflcc->march_opt = CFLAGS_OPT;
+
+ /* callname & if C++ mode */
+
+ aflcc->argv0 = ck_strdup(argv0);
+
+ char *cname = NULL;
+
+ if ((cname = strrchr(aflcc->argv0, '/')) != NULL) {
+
+ cname++;
+
+ } else {
+
+ cname = aflcc->argv0;
+
+ }
+
+ aflcc->callname = cname;
+
+ if (strlen(cname) > 2 && (strncmp(cname + strlen(cname) - 2, "++", 2) == 0 ||
+ strstr(cname, "-g++") != NULL)) {
+
+ aflcc->plusplus_mode = 1;
+
+ }
+
+ /* debug */
+
+ if (getenv("AFL_DEBUG")) {
+
+ aflcc->debug = 1;
+ if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
+
+ } else if (getenv("AFL_QUIET")) {
+
+ be_quiet = 1;
+
+ }
+
+ if ((getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) && (!aflcc->debug)) {
+
+ be_quiet = 1;
+
+ }
+
+}
+
+/*
+ Try to find a specific runtime we need, in here:
+
+ 1. firstly we check the $AFL_PATH environment variable location if set
+ 2. next we check argv[0] if it has path information and use it
a) we also check ../lib/afl
- 4. if 3. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
+ 3. if 2. failed we check /proc (only Linux, Android, NetBSD, DragonFly, and
FreeBSD with procfs)
a) and check here in ../lib/afl too
- 5. we look into the AFL_PATH define (usually /usr/local/lib/afl)
- 6. we finally try the current directory
+ 4. we look into the AFL_PATH define (usually /usr/local/lib/afl)
+ 5. we finally try the current directory
if all these attempts fail - we return NULL and the caller has to decide
- what to do.
+ what to do. Otherwise the path to obj would be allocated and returned.
*/
+u8 *find_object(aflcc_state_t *aflcc, u8 *obj) {
-static u8 *find_object(u8 *obj, u8 *argv0) {
+ u8 *argv0 = aflcc->argv0;
u8 *afl_path = getenv("AFL_PATH");
u8 *slash = NULL, *tmp;
@@ -164,14 +394,9 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
tmp = alloc_printf("%s/%s", afl_path, obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
-
- if (!access(tmp, R_OK)) {
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- obj_path = afl_path;
- return tmp;
-
- }
+ if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
@@ -190,11 +415,11 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
tmp = alloc_printf("%s/%s", dir, obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
if (!access(tmp, R_OK)) {
- obj_path = dir;
+ ck_free(dir);
return tmp;
}
@@ -202,12 +427,10 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
ck_free(tmp);
tmp = alloc_printf("%s/../lib/afl/%s", dir, obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
if (!access(tmp, R_OK)) {
- u8 *dir2 = alloc_printf("%s/../lib/afl", dir);
- obj_path = dir2;
ck_free(dir);
return tmp;
@@ -247,26 +470,18 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
*slash = 0;
tmp = alloc_printf("%s/%s", exepath, obj);
- if (!access(tmp, R_OK)) {
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- u8 *dir = alloc_printf("%s", exepath);
- obj_path = dir;
- return tmp;
-
- }
+ if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
tmp = alloc_printf("%s/../lib/afl/%s", exepath, obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
-
- if (!access(tmp, R_OK)) {
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- u8 *dir = alloc_printf("%s/../lib/afl/", exepath);
- obj_path = dir;
- return tmp;
+ if (!access(tmp, R_OK)) { return tmp; }
- }
+ ck_free(tmp);
}
@@ -283,432 +498,962 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
tmp = alloc_printf("%s/%s", AFL_PATH, obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- if (!access(tmp, R_OK)) {
+ if (!access(tmp, R_OK)) { return tmp; }
- obj_path = AFL_PATH;
- return tmp;
+ ck_free(tmp);
+ tmp = alloc_printf("./%s", obj);
- }
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
+
+ if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
- tmp = alloc_printf("./%s", obj);
+ if (aflcc->debug) DEBUGF("Trying ... giving up\n");
- if (debug) DEBUGF("Trying %s\n", tmp);
+ return NULL;
- if (!access(tmp, R_OK)) {
+}
+
+/*
+ Deduce some info about compiler toolchains in current system,
+ from the building results of AFL++
+*/
+void find_built_deps(aflcc_state_t *aflcc) {
+
+ char *ptr = NULL;
- obj_path = ".";
- return tmp;
+#if defined(__x86_64__) || defined(__i386__)
+ if ((ptr = find_object(aflcc, "afl-as")) != NULL) {
+
+ #ifndef __APPLE__
+ // on OSX clang masquerades as GCC
+ aflcc->have_gcc = 1;
+ #endif
+ aflcc->have_clang = 1;
+ ck_free(ptr);
}
- ck_free(tmp);
+#endif
- if (debug) DEBUGF("Trying ... giving up\n");
+ if ((ptr = find_object(aflcc, "SanitizerCoveragePCGUARD.so")) != NULL) {
- return NULL;
+ aflcc->have_optimized_pcguard = 1;
+ ck_free(ptr);
+
+ }
+
+#if (LLVM_MAJOR >= 3)
+
+ if ((ptr = find_object(aflcc, "SanitizerCoverageLTO.so")) != NULL) {
+
+ aflcc->have_lto = 1;
+ ck_free(ptr);
+
+ }
+
+ if ((ptr = find_object(aflcc, "cmplog-routines-pass.so")) != NULL) {
+
+ aflcc->have_llvm = 1;
+ ck_free(ptr);
+
+ }
+
+#endif
+
+#ifdef __ANDROID__
+ aflcc->have_llvm = 1;
+#endif
+
+ if ((ptr = find_object(aflcc, "afl-gcc-pass.so")) != NULL) {
+
+ aflcc->have_gcc_plugin = 1;
+ ck_free(ptr);
+
+ }
+
+#if !defined(__ANDROID__) && !defined(ANDROID)
+ ptr = find_object(aflcc, "afl-compiler-rt.o");
+
+ if (!ptr) {
+
+ FATAL(
+ "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
+ "environment variable.");
+
+ }
+
+ if (aflcc->debug) { DEBUGF("rt=%s\n", ptr); }
+
+ ck_free(ptr);
+#endif
}
-void parse_fsanitize(char *string) {
+/** compiler_mode & instrument_mode selecting -----BEGIN----- **/
- char *p, *ptr = string + strlen("-fsanitize=");
- char *new = malloc(strlen(string) + 1);
- char *tmp = malloc(strlen(ptr));
- u32 count = 0, len, ende = 0;
+/* Select compiler_mode by callname, such as "afl-clang-fast", etc. */
+void compiler_mode_by_callname(aflcc_state_t *aflcc) {
- if (!new || !tmp) { FATAL("could not acquire memory"); }
- strcpy(new, "-fsanitize=");
+ if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
- do {
+ /* afl-clang-fast is always created there by makefile
+ just like afl-clang, burdened with special purposes:
+ - If llvm-config is not available (i.e. LLVM_MAJOR is 0),
+ or too old, it falls back to LLVM-NATIVE mode and let
+ the actual compiler complain if doesn't work.
+ - Otherwise try default llvm instruments except LTO.
+ */
+#if (LLVM_MAJOR >= 3)
+ aflcc->compiler_mode = LLVM;
+#else
+ aflcc->compiler_mode = CLANG;
+#endif
- p = strchr(ptr, ',');
- if (!p) {
+ } else
- p = ptr + strlen(ptr) + 1;
- ende = 1;
+#if (LLVM_MAJOR >= 3)
+
+ if (strncmp(aflcc->callname, "afl-clang-lto", 13) == 0 ||
+
+ strncmp(aflcc->callname, "afl-lto", 7) == 0) {
+
+ aflcc->compiler_mode = LTO;
+
+ } else
+
+#endif
+
+ if (strncmp(aflcc->callname, "afl-gcc-fast", 12) == 0 ||
+
+ strncmp(aflcc->callname, "afl-g++-fast", 12) == 0) {
+
+ aflcc->compiler_mode = GCC_PLUGIN;
+
+ } else if (strncmp(aflcc->callname, "afl-gcc", 7) == 0 ||
+
+ strncmp(aflcc->callname, "afl-g++", 7) == 0) {
+
+ aflcc->compiler_mode = GCC;
+
+ } else if (strcmp(aflcc->callname, "afl-clang") == 0 ||
+
+ strcmp(aflcc->callname, "afl-clang++") == 0) {
+
+ aflcc->compiler_mode = CLANG;
+
+ }
+
+}
+
+/*
+ Select compiler_mode by env AFL_CC_COMPILER. And passthrough mode can be
+ regarded as a special compiler_mode, so we check for it here, too.
+*/
+void compiler_mode_by_environ(aflcc_state_t *aflcc) {
+
+ if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
+
+ aflcc->passthrough = 1;
+
+ }
+
+ char *ptr = getenv("AFL_CC_COMPILER");
+
+ if (!ptr) { return; }
+
+ if (aflcc->compiler_mode) {
+
+ if (!be_quiet) {
+
+ WARNF(
+ "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
+ "selected by command line parameter or symlink, ignoring the "
+ "environment variable!");
}
- len = p - ptr;
- if (len) {
+ } else {
- strncpy(tmp, ptr, len);
- tmp[len] = 0;
- // fprintf(stderr, "Found: %s\n", tmp);
- ptr += len + 1;
- if (*tmp) {
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
- u32 copy = 1;
- if (!strcmp(tmp, "fuzzer")) {
+ aflcc->compiler_mode = LTO;
- need_aflpplib = 1;
- copy = 0;
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
- } else if (!strncmp(tmp, "fuzzer", 6)) {
+ aflcc->compiler_mode = LLVM;
- copy = 0;
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
- }
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
- if (copy) {
+ aflcc->compiler_mode = GCC_PLUGIN;
- if (count) { strcat(new, ","); }
- strcat(new, tmp);
- ++count;
+ } else if (strcasecmp(ptr, "GCC") == 0) {
- }
+ aflcc->compiler_mode = GCC;
+
+ } else if (strcasecmp(ptr, "CLANG") == 0) {
+
+ aflcc->compiler_mode = CLANG;
+
+ } else
+
+ FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
+
+ }
+
+}
+
+/*
+ Select compiler_mode by command line options --afl-...
+ If it can be inferred, instrument_mode would also be set.
+ This can supersedes previous result based on callname
+ or AFL_CC_COMPILER. And "--afl_noopt"/"--afl-noopt" will
+ be overwritten by "-g".
+*/
+void compiler_mode_by_cmdline(aflcc_state_t *aflcc, int argc, char **argv) {
+
+ char *ptr = NULL;
+
+ for (int i = 1; i < argc; i++) {
+
+ if (strncmp(argv[i], "--afl", 5) == 0) {
+
+ if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
+
+ aflcc->passthrough = 1;
+ argv[i] = "-g"; // we have to overwrite it, -g is always good
+ continue;
}
- } else {
+ if (aflcc->compiler_mode && !be_quiet) {
- ptr++; /*fprintf(stderr, "NO!\n"); */
+ WARNF(
+ "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
+ "symlink compiler selection!");
- }
+ }
- } while (!ende);
+ ptr = argv[i];
+ ptr += 5;
+ while (*ptr == '-')
+ ptr++;
- strcpy(string, new);
- // fprintf(stderr, "string: %s\n", string);
- // fprintf(stderr, "new: %s\n", new);
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
+
+ aflcc->compiler_mode = LTO;
+
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+
+ aflcc->compiler_mode = LLVM;
+
+ } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
+
+ strncasecmp(ptr, "PC-GUARD", 8) == 0) {
+
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+ } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
+
+ strcasecmp(ptr, "CFG") == 0) {
+
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
+
+ } else if (strcasecmp(ptr, "AFL") == 0 ||
+
+ strcasecmp(ptr, "CLASSIC") == 0) {
+
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
+
+ } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
+
+ strcasecmp(ptr, "NATIVE") == 0 ||
+ strcasecmp(ptr, "LLVM-NATIVE") == 0) {
+
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
+
+ aflcc->compiler_mode = GCC_PLUGIN;
+
+ } else if (strcasecmp(ptr, "GCC") == 0) {
+
+ aflcc->compiler_mode = GCC;
+
+ } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
+
+ aflcc->compiler_mode = CLANG;
+
+ } else
+
+ FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
+
+ }
+
+ }
}
-static u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0,
- shared_linking = 0, preprocessor_only = 0, have_unroll = 0,
- have_o = 0, have_pic = 0, have_c = 0, partial_linking = 0,
- non_dash = 0;
+/*
+ Select instrument_mode by those envs in old style:
+ - USE_TRACE_PC, AFL_USE_TRACE_PC, AFL_LLVM_USE_TRACE_PC, AFL_TRACE_PC
+ - AFL_LLVM_CALLER, AFL_LLVM_CTX, AFL_LLVM_CTX_K
+ - AFL_LLVM_NGRAM_SIZE
+*/
+static void instrument_mode_old_environ(aflcc_state_t *aflcc) {
+
+ if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
+ getenv("INSTRIM_LIB")) {
+
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
+ "(default in afl-cc).\n");
+
+ }
+
+ if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
+ getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
+
+ if (aflcc->instrument_mode == 0)
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+ else if (aflcc->instrument_mode != INSTRUMENT_PCGUARD)
+ FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
+
+ }
+
+ if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_LTO_CALLER") ||
+ getenv("AFL_LLVM_LTO_CTX"))
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
-static void process_params(u32 argc, char **argv) {
+ if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
+ aflcc->ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
+ if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX)
+ FATAL(
+ "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
+ "(%u)",
+ NGRAM_SIZE_MAX);
- if (cc_par_cnt + argc >= 1024) { FATAL("Too many command line parameters"); }
+ }
+
+ if (getenv("AFL_LLVM_CTX_K")) {
+
+ aflcc->ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
+ if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
+ FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
+ CTX_MAX_K);
+ if (aflcc->ctx_k == 1) {
- if (lto_mode && argc > 1) {
+ setenv("AFL_LLVM_CALLER", "1", 1);
+ unsetenv("AFL_LLVM_CTX_K");
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- u32 idx;
- for (idx = 1; idx < argc; idx++) {
+ } else {
- if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
}
}
- // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
+}
- /* Process the argument list. */
+/*
+ Select instrument_mode by env 'AFL_LLVM_INSTRUMENT'.
+ Previous compiler_mode will be superseded, if required by some
+ values of instrument_mode.
+*/
+static void instrument_mode_new_environ(aflcc_state_t *aflcc) {
- u8 skip_next = 0;
- while (--argc) {
+ if (!getenv("AFL_LLVM_INSTRUMENT")) { return; }
- u8 *cur = *(++argv);
+ u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
- if (skip_next) {
+ while (ptr2) {
- skip_next = 0;
- continue;
+ if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
+ strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
+
+ if (aflcc->instrument_mode == INSTRUMENT_LTO) {
+
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
+ aflcc->lto_mode = 1;
+
+ } else if (!aflcc->instrument_mode ||
+
+ aflcc->instrument_mode == INSTRUMENT_AFL) {
+
+ aflcc->instrument_mode = INSTRUMENT_AFL;
+
+ } else {
+
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
+
+ }
}
- if (cur[0] != '-') { non_dash = 1; }
- if (!strncmp(cur, "--afl", 5)) continue;
+ if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
+ strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
- if (lto_mode && !strncmp(cur, "-flto=thin", 10)) {
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_PCGUARD)
- FATAL(
- "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
- "use afl-clang-fast!");
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
- if (lto_mode && !strncmp(cur, "-fuse-ld=", 9)) continue;
- if (lto_mode && !strncmp(cur, "--ld-path=", 10)) continue;
- if (!strncmp(cur, "-fno-unroll", 11)) continue;
- if (strstr(cur, "afl-compiler-rt") || strstr(cur, "afl-llvm-rt")) continue;
- if (!strcmp(cur, "-Wl,-z,defs") || !strcmp(cur, "-Wl,--no-undefined") ||
- !strcmp(cur, "--no-undefined")) {
+ if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
+ strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
+ strncasecmp(ptr2, "native", strlen("native")) == 0) {
- continue;
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE)
+
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
- if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
+ if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
+ strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
- if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
- u8 *param = *(argv + 1);
- if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
- skip_next = 1;
- continue;
+ } else {
+
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
}
- if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
- !strncmp(cur, "-stdlib=", 8)) {
+ if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
+ strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
}
- if (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
+ if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
- have_instr_list = 1;
+ aflcc->lto_mode = 1;
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_LTO)
+
+ aflcc->instrument_mode = INSTRUMENT_LTO;
+
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
- if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
- strchr(cur, ',')) {
+ if (strcasecmp(ptr2, "gcc") == 0) {
- parse_fsanitize(cur);
- if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_GCC)
- } else if ((!strncmp(cur, "-fsanitize=fuzzer-",
+ aflcc->instrument_mode = INSTRUMENT_GCC;
- strlen("-fsanitize=fuzzer-")) ||
- !strncmp(cur, "-fsanitize-coverage",
- strlen("-fsanitize-coverage"))) &&
- (strncmp(cur, "sanitize-coverage-allow",
- strlen("sanitize-coverage-allow")) &&
- strncmp(cur, "sanitize-coverage-deny",
- strlen("sanitize-coverage-deny")) &&
- instrument_mode != INSTRUMENT_LLVMNATIVE)) {
+ else if (aflcc->instrument_mode != INSTRUMENT_GCC)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
+ aflcc->compiler_mode = GCC;
}
- if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
+ if (strcasecmp(ptr2, "clang") == 0) {
- u8 *afllib = find_object("libAFLDriver.a", argv[0]);
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_CLANG)
- if (!be_quiet) {
+ aflcc->instrument_mode = INSTRUMENT_CLANG;
- OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
+ else if (aflcc->instrument_mode != INSTRUMENT_CLANG)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
- }
+ aflcc->compiler_mode = CLANG;
- if (!afllib) {
+ }
- if (!be_quiet) {
+ if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
+ strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
+ strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
- WARNF(
- "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
- "the flags - this will fail!");
+ u8 *ptr3 = ptr2;
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
+ ptr3++;
- }
+ if (!*ptr3) {
+
+ if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
+ FATAL(
+ "you must set the K-CTX K with (e.g. for value 2) "
+ "AFL_LLVM_INSTRUMENT=ctx-2");
+
+ }
+
+ aflcc->ctx_k = atoi(ptr3);
+ if (aflcc->ctx_k < 1 || aflcc->ctx_k > CTX_MAX_K)
+ FATAL(
+ "K-CTX instrumentation option must be between 1 and CTX_MAX_K "
+ "(%u)",
+ CTX_MAX_K);
+
+ if (aflcc->ctx_k == 1) {
+
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ setenv("AFL_LLVM_CALLER", "1", 1);
+ unsetenv("AFL_LLVM_CTX_K");
} else {
- cc_params[cc_par_cnt++] = afllib;
+ aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
+ u8 *ptr4 = alloc_printf("%u", aflcc->ctx_k);
+ setenv("AFL_LLVM_CTX_K", ptr4, 1);
-#ifdef __APPLE__
- cc_params[cc_par_cnt++] = "-undefined";
- cc_params[cc_par_cnt++] = "dynamic_lookup";
-#endif
+ }
+
+ }
+
+ if (strcasecmp(ptr2, "ctx") == 0) {
+
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ setenv("AFL_LLVM_CTX", "1", 1);
+
+ }
+
+ if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
+
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ setenv("AFL_LLVM_CALLER", "1", 1);
+
+ }
+
+ if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
+
+ u8 *ptr3 = ptr2 + strlen("ngram");
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) {
+
+ ptr3++;
}
- if (need_aflpplib) {
+ if (!*ptr3) {
- need_aflpplib = 0;
+ if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL)
+ FATAL(
+ "you must set the NGRAM size with (e.g. for value 2) "
+ "AFL_LLVM_INSTRUMENT=ngram-2");
- } else {
+ }
- continue;
+ aflcc->ngram_size = atoi(ptr3);
+
+ if (aflcc->ngram_size < 2 || aflcc->ngram_size > NGRAM_SIZE_MAX) {
+
+ FATAL(
+ "NGRAM instrumentation option must be between 2 and "
+ "NGRAM_SIZE_MAX (%u)",
+ NGRAM_SIZE_MAX);
}
+ aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
+ u8 *ptr4 = alloc_printf("%u", aflcc->ngram_size);
+ setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1);
+
}
- if (!strcmp(cur, "-m32")) bit_mode = 32;
- if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
- if (!strcmp(cur, "-m64")) bit_mode = 64;
+ ptr2 = strtok(NULL, ":,;");
- if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
- asan_set = 1;
+ }
- if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
+}
- if (!strcmp(cur, "-x")) x_set = 1;
- if (!strcmp(cur, "-E")) preprocessor_only = 1;
- if (!strcmp(cur, "-shared")) shared_linking = 1;
- if (!strcmp(cur, "-dynamiclib")) shared_linking = 1;
- if (!strcmp(cur, "--target=wasm32-wasi")) passthrough = 1;
- if (!strcmp(cur, "-Wl,-r")) partial_linking = 1;
- if (!strcmp(cur, "-Wl,-i")) partial_linking = 1;
- if (!strcmp(cur, "-Wl,--relocatable")) partial_linking = 1;
- if (!strcmp(cur, "-r")) partial_linking = 1;
- if (!strcmp(cur, "--relocatable")) partial_linking = 1;
- if (!strcmp(cur, "-c")) have_c = 1;
+/*
+ Select instrument_mode by envs, the top wrapper. We check
+ have_instr_env firstly, then call instrument_mode_old_environ
+ and instrument_mode_new_environ sequentially.
+*/
+void instrument_mode_by_environ(aflcc_state_t *aflcc) {
- if (!strncmp(cur, "-O", 2)) have_o = 1;
- if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
+ if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
+ getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
+ getenv("AFL_LLVM_BLOCKLIST")) {
- if (*cur == '@') {
+ aflcc->have_instr_env = 1;
- // response file support.
- // we have two choices - move everything to the command line or
- // rewrite the response files to temporary files and delete them
- // afterwards. We choose the first for easiness.
- // We do *not* support quotes in the rsp files to cope with spaces in
- // filenames etc! If you need that then send a patch!
- u8 *filename = cur + 1;
- if (debug) { DEBUGF("response file=%s\n", filename); }
- FILE *f = fopen(filename, "r");
- struct stat st;
+ }
- // Check not found or empty? let the compiler complain if so.
- if (!f || fstat(fileno(f), &st) < 0 || st.st_size < 1) {
+ if (aflcc->have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
- cc_params[cc_par_cnt++] = cur;
- continue;
+ WARNF(
+ "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
+ "for file matching, only function matching!");
- }
+ }
- u8 *tmpbuf = malloc(st.st_size + 1), *ptr;
- char **args = malloc(sizeof(char *) * (st.st_size >> 1));
- int count = 1, cont = 0, cont_act = 0;
+ instrument_mode_old_environ(aflcc);
+ instrument_mode_new_environ(aflcc);
- while (fgets(tmpbuf, st.st_size, f)) {
+}
- ptr = tmpbuf;
- // no leading whitespace
- while (isspace(*ptr)) {
+/*
+ Workaround to ensure CALLER, CTX, K-CTX and NGRAM
+ instrumentation were used correctly.
+*/
+static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
- ++ptr;
- cont_act = 0;
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
- }
+ FATAL("you cannot set CTX and CALLER together");
- // no comments, no empty lines
- if (*ptr == '#' || *ptr == '\n' || !*ptr) { continue; }
- // remove LF
- if (ptr[strlen(ptr) - 1] == '\n') { ptr[strlen(ptr) - 1] = 0; }
- // remove CR
- if (*ptr && ptr[strlen(ptr) - 1] == '\r') { ptr[strlen(ptr) - 1] = 0; }
- // handle \ at end of line
- if (*ptr && ptr[strlen(ptr) - 1] == '\\') {
+ }
- cont = 1;
- ptr[strlen(ptr) - 1] = 0;
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
- }
+ FATAL("you cannot set CTX and K-CTX together");
- // remove whitespace at end
- while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
+ }
- ptr[strlen(ptr) - 1] = 0;
- cont = 0;
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
- }
+ FATAL("you cannot set CALLER and K-CTX together");
- if (*ptr) {
+ }
- do {
+ if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM &&
+ !((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
+ aflcc->compiler_mode == LTO))
+ FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
- u8 *value = ptr;
- while (*ptr && !isspace(*ptr)) {
+ if (aflcc->instrument_opt_mode &&
+ aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
+ aflcc->instrument_mode != INSTRUMENT_CLASSIC &&
+ !(aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER &&
+ aflcc->compiler_mode == LTO))
+ FATAL(
+ "CALLER, CTX and NGRAM instrumentation options can only be used with "
+ "the LLVM CLASSIC instrumentation mode.");
- ++ptr;
+}
- }
+/*
+ Last step of compiler_mode & instrument_mode selecting.
+ We have a few of workarounds here, to check any corner cases,
+ prepare for a series of fallbacks, and raise warnings or errors.
+*/
+void mode_final_checkout(aflcc_state_t *aflcc, int argc, char **argv) {
- while (*ptr && isspace(*ptr)) {
+ if (aflcc->instrument_opt_mode &&
+ aflcc->instrument_mode == INSTRUMENT_DEFAULT &&
+ (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == UNSET)) {
- *ptr++ = 0;
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
+ aflcc->compiler_mode = LLVM;
- }
+ }
- if (cont_act) {
+ if (!aflcc->compiler_mode) {
- u32 len = strlen(args[count - 1]) + strlen(value) + 1;
- u8 *tmp = malloc(len);
- snprintf(tmp, len, "%s%s", args[count - 1], value);
- free(args[count - 1]);
- args[count - 1] = tmp;
- cont_act = 0;
+ // lto is not a default because outside of afl-cc RANLIB and AR have to
+ // be set to LLVM versions so this would work
+ if (aflcc->have_llvm)
+ aflcc->compiler_mode = LLVM;
+ else if (aflcc->have_gcc_plugin)
+ aflcc->compiler_mode = GCC_PLUGIN;
+ else if (aflcc->have_gcc)
+ aflcc->compiler_mode = GCC;
+ else if (aflcc->have_clang)
+ aflcc->compiler_mode = CLANG;
+ else if (aflcc->have_lto)
+ aflcc->compiler_mode = LTO;
+ else
+ FATAL("no compiler mode available");
- } else {
+ }
- args[count++] = strdup(value);
+ switch (aflcc->compiler_mode) {
+
+ case GCC:
+ if (!aflcc->have_gcc) FATAL("afl-gcc is not available on your platform!");
+ break;
+ case CLANG:
+ if (!aflcc->have_clang)
+ FATAL("afl-clang is not available on your platform!");
+ break;
+ case LLVM:
+ if (!aflcc->have_llvm)
+ FATAL(
+ "LLVM mode is not available, please install LLVM 13+ and recompile "
+ "AFL++");
+ break;
+ case GCC_PLUGIN:
+ if (!aflcc->have_gcc_plugin)
+ FATAL(
+ "GCC_PLUGIN mode is not available, install gcc plugin support and "
+ "recompile AFL++");
+ break;
+ case LTO:
+ if (!aflcc->have_lto)
+ FATAL(
+ "LTO mode is not available, please install LLVM 13+ and lld of the "
+ "same version and recompile AFL++");
+ break;
+ default:
+ FATAL("no compiler mode available");
- }
+ }
- } while (*ptr);
+ if (aflcc->compiler_mode == GCC) { aflcc->instrument_mode = INSTRUMENT_GCC; }
- }
+ if (aflcc->compiler_mode == CLANG) {
- if (cont) {
+ /* if our PCGUARD implementation is not available then silently switch to
+ native LLVM PCGUARD. Or classic asm instrument is explicitly preferred. */
+ if (!aflcc->have_optimized_pcguard &&
+ (aflcc->instrument_mode == INSTRUMENT_DEFAULT ||
+ aflcc->instrument_mode == INSTRUMENT_PCGUARD)) {
- cont_act = 1;
- cont = 0;
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- }
+ } else {
- }
+ aflcc->instrument_mode = INSTRUMENT_CLANG;
+ setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
- if (count) { process_params(count, args); }
+ }
- // we cannot free args[]
- free(tmpbuf);
+ }
- continue;
+ if (aflcc->compiler_mode == LTO) {
+
+ if (aflcc->instrument_mode == 0 ||
+ aflcc->instrument_mode == INSTRUMENT_LTO ||
+ aflcc->instrument_mode == INSTRUMENT_CFG ||
+ aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
+
+ aflcc->lto_mode = 1;
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+ } else if (aflcc->instrument_mode == INSTRUMENT_CLASSIC) {
+
+ aflcc->lto_mode = 1;
+
+ } else {
+
+ if (!be_quiet) {
+
+ WARNF("afl-clang-lto called with mode %s, using that mode instead",
+ instrument_mode_2str(aflcc->instrument_mode));
+
+ }
}
- cc_params[cc_par_cnt++] = cur;
+ }
+
+ if (aflcc->instrument_mode == 0 && aflcc->compiler_mode < GCC_PLUGIN) {
+
+#if LLVM_MAJOR >= 7
+ #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+ if (aflcc->have_instr_env) {
+
+ aflcc->instrument_mode = INSTRUMENT_AFL;
+ if (!be_quiet) {
+
+ WARNF(
+ "Switching to classic instrumentation because "
+ "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
+
+ }
+
+ } else
+
+ #endif
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+#else
+ aflcc->instrument_mode = INSTRUMENT_AFL;
+#endif
}
-}
+ if (!aflcc->instrument_opt_mode && aflcc->lto_mode &&
+ aflcc->instrument_mode == INSTRUMENT_CFG) {
-/* Copy argv to cc_params, making the necessary edits. */
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
-static void edit_params(u32 argc, char **argv, char **envp) {
+ }
- cc_params = ck_alloc(1024 * sizeof(u8 *));
+#ifndef AFL_CLANG_FLTO
+ if (aflcc->lto_mode)
+ FATAL(
+ "instrumentation mode LTO specified but LLVM support not available "
+ "(requires LLVM 11 or higher)");
+#endif
- if (lto_mode) {
+ if (aflcc->lto_mode) {
- if (lto_flag[0] != '-')
+ if (aflcc->lto_flag[0] != '-')
FATAL(
"Using afl-clang-lto is not possible because Makefile magic did not "
"identify the correct -flto flag");
else
- compiler_mode = LTO;
+ aflcc->compiler_mode = LTO;
}
- if (plusplus_mode) {
+ if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
+ FATAL(
+ "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
+ "together");
- u8 *alt_cxx = getenv("AFL_CXX");
+#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
- if (!alt_cxx) {
+ if (aflcc->instrument_mode == INSTRUMENT_PCGUARD && aflcc->have_instr_env) {
+
+ FATAL(
+ "Instrumentation type PCGUARD does not support "
+ "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
- if (compiler_mode >= GCC_PLUGIN) {
+ }
- if (compiler_mode == GCC) {
+#endif
- alt_cxx = clang_mode ? "clang++" : "g++";
+ instrument_opt_mode_exclude(aflcc);
- } else if (compiler_mode == CLANG) {
+ u8 *ptr2;
- alt_cxx = "clang++";
+ if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
+ FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
- } else {
+ if (getenv("AFL_LLVM_LAF_ALL")) {
- alt_cxx = "g++";
+ setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1);
+ setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1);
+ setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1);
+ setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1);
- }
+ }
+
+ if (getenv("AFL_LLVM_DICT2FILE") &&
+ (getenv("AFL_LLVM_LAF_SPLIT_SWITCHES") ||
+ getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
+ getenv("AFL_LLVM_LAF_SPLIT_FLOATS") ||
+ getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")))
+ FATAL("AFL_LLVM_DICT2FILE is incompatible with AFL_LLVM_LAF_*");
+
+ aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
+ getenv("AFL_GCC_CMPLOG");
+
+}
+
+/*
+ Print welcome message on screen, giving brief notes about
+ compiler_mode and instrument_mode.
+*/
+void mode_notification(aflcc_state_t *aflcc) {
+
+ char *ptr2 = alloc_printf(" + NGRAM-%u", aflcc->ngram_size);
+ char *ptr3 = alloc_printf(" + K-CTX-%u", aflcc->ctx_k);
+
+ char *ptr1 = alloc_printf(
+ "%s%s%s%s%s", instrument_mode_2str(aflcc->instrument_mode),
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
+
+ ck_free(ptr2);
+ ck_free(ptr3);
+
+ if ((isatty(2) && !be_quiet) || aflcc->debug) {
+
+ SAYF(cCYA
+ "afl-cc" VERSION cRST
+ " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n",
+ compiler_mode_2str(aflcc->compiler_mode), ptr1);
+
+ }
+
+ ck_free(ptr1);
+
+ if (!be_quiet &&
+ (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)) {
+
+ WARNF(
+ "You are using outdated instrumentation, install LLVM and/or "
+ "gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast "
+ "instead!");
+
+ }
+
+}
+
+/*
+ Set argv[0] required by execvp. It can be
+ - specified by env AFL_CXX
+ - g++ or clang++
+ - CLANGPP_BIN or LLVM_BINDIR/clang++
+ when in C++ mode, or
+ - specified by env AFL_CC
+ - gcc or clang
+ - CLANG_BIN or LLVM_BINDIR/clang
+ otherwise.
+*/
+void add_real_argv0(aflcc_state_t *aflcc) {
+
+ static u8 llvm_fullpath[PATH_MAX];
+
+ if (aflcc->plusplus_mode) {
+
+ u8 *alt_cxx = getenv("AFL_CXX");
+
+ if (!alt_cxx) {
+
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
+
+ alt_cxx = "g++";
+
+ } else if (aflcc->compiler_mode == CLANG) {
+
+ alt_cxx = "clang++";
} else {
@@ -723,7 +1468,7 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
- cc_params[0] = alt_cxx;
+ aflcc->cc_params[0] = alt_cxx;
} else {
@@ -731,21 +1476,13 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (!alt_cc) {
- if (compiler_mode >= GCC_PLUGIN) {
-
- if (compiler_mode == GCC) {
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
- alt_cc = clang_mode ? "clang" : "gcc";
+ alt_cc = "gcc";
- } else if (compiler_mode == CLANG) {
+ } else if (aflcc->compiler_mode == CLANG) {
- alt_cc = "clang";
-
- } else {
-
- alt_cc = "gcc";
-
- }
+ alt_cc = "clang";
} else {
@@ -753,1319 +1490,1284 @@ static void edit_params(u32 argc, char **argv, char **envp) {
snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
LLVM_BINDIR);
else
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s", CLANG_BIN);
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
alt_cc = llvm_fullpath;
}
}
- cc_params[0] = alt_cc;
+ aflcc->cc_params[0] = alt_cc;
}
- if (compiler_mode == GCC || compiler_mode == CLANG) {
+}
- cc_params[cc_par_cnt++] = "-B";
- cc_params[cc_par_cnt++] = obj_path;
+/** compiler_mode & instrument_mode selecting -----END----- **/
- if (clang_mode || compiler_mode == CLANG) {
+/** Macro defs for the preprocessor -----BEGIN----- **/
- cc_params[cc_par_cnt++] = "-no-integrated-as";
+void add_defs_common(aflcc_state_t *aflcc) {
- }
+ insert_param(aflcc, "-D__AFL_COMPILER=1");
+ insert_param(aflcc, "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1");
- }
-
- if (compiler_mode == GCC_PLUGIN) {
+}
- char *fplugin_arg;
+/*
+ __afl_coverage macro defs. See
+ instrumentation/README.instrument_list.md#
+ 2-selective-instrumentation-with-_afl_coverage-directives
+*/
+void add_defs_selective_instr(aflcc_state_t *aflcc) {
- if (cmplog_mode) {
+ if (aflcc->plusplus_mode) {
- fplugin_arg =
- alloc_printf("-fplugin=%s/afl-gcc-cmplog-pass.so", obj_path);
- cc_params[cc_par_cnt++] = fplugin_arg;
- fplugin_arg =
- alloc_printf("-fplugin=%s/afl-gcc-cmptrs-pass.so", obj_path);
- cc_params[cc_par_cnt++] = fplugin_arg;
+ insert_param(aflcc,
+ "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
+ "extern \"C\" void __afl_coverage_discard();"
+ "extern \"C\" void __afl_coverage_skip();"
+ "extern \"C\" void __afl_coverage_on();"
+ "extern \"C\" void __afl_coverage_off();");
- }
+ } else {
- fplugin_arg = alloc_printf("-fplugin=%s/afl-gcc-pass.so", obj_path);
- cc_params[cc_par_cnt++] = fplugin_arg;
- cc_params[cc_par_cnt++] = "-fno-if-conversion";
- cc_params[cc_par_cnt++] = "-fno-if-conversion2";
+ insert_param(aflcc,
+ "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
+ "void __afl_coverage_discard();"
+ "void __afl_coverage_skip();"
+ "void __afl_coverage_on();"
+ "void __afl_coverage_off();");
}
- if (compiler_mode == LLVM || compiler_mode == LTO) {
+ insert_param(
+ aflcc,
+ "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
+ "1;");
+ insert_param(aflcc, "-D__AFL_COVERAGE_ON()=__afl_coverage_on()");
+ insert_param(aflcc, "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()");
+ insert_param(aflcc, "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()");
+ insert_param(aflcc, "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()");
- cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+}
- if (lto_mode && have_instr_env) {
+/*
+ Macro defs for persistent mode. As documented in
+ instrumentation/README.persistent_mode.md, deferred forkserver initialization
+ and persistent mode are not available in afl-gcc and afl-clang.
+*/
+void add_defs_persistent_mode(aflcc_state_t *aflcc) {
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] = alloc_printf(
- "-fpass-plugin=%s/afl-llvm-lto-instrumentlist.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-llvm-lto-instrumentlist.so", obj_path);
-#endif
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) return;
- }
+ insert_param(aflcc, "-D__AFL_HAVE_MANUAL_CONTROL=1");
- if (getenv("AFL_LLVM_DICT2FILE")) {
+ /* When the user tries to use persistent or deferred forkserver modes by
+ appending a single line to the program, we want to reliably inject a
+ signature into the binary (to be picked up by afl-fuzz) and we want
+ to call a function from the runtime .o file. This is unnecessarily
+ painful for three reasons:
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/afl-llvm-dict2file.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-llvm-dict2file.so", obj_path);
-#endif
+ 1) We need to convince the compiler not to optimize out the signature.
+ This is done with __attribute__((used)).
- }
+ 2) We need to convince the linker, when called with -Wl,--gc-sections,
+ not to do the same. This is done by forcing an assignment to a
+ 'volatile' pointer.
- // laf
- if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
+ 3) We need to declare __afl_persistent_loop() in the global namespace,
+ but doing this within a method in a class is hard - :: and extern "C"
+ are forbidden and __attribute__((alias(...))) doesn't work. Hence the
+ __asm__ aliasing trick.
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/split-switches-pass.so", obj_path);
-#endif
+ */
- }
+ insert_param(aflcc,
+ "-D__AFL_FUZZ_INIT()="
+ "int __afl_sharedmem_fuzzing = 1;"
+ "extern __attribute__((visibility(\"default\"))) "
+ "unsigned int *__afl_fuzz_len;"
+ "extern __attribute__((visibility(\"default\"))) "
+ "unsigned char *__afl_fuzz_ptr;"
+ "unsigned char __afl_fuzz_alt[1048576];"
+ "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;");
- if (getenv("LAF_TRANSFORM_COMPARES") ||
- getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
+ insert_param(aflcc,
+ "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
+ "__afl_fuzz_alt_ptr)");
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/compare-transform-pass.so", obj_path);
+ insert_param(
+ aflcc,
+ "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
+ "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
+ "? 0 : *__afl_fuzz_len)");
+
+ insert_param(
+ aflcc,
+ "-D__AFL_LOOP(_A)="
+ "({ static volatile const char *_B __attribute__((used,unused)); "
+ " _B = (const char*)\"" PERSIST_SIG
+ "\"; "
+ "extern __attribute__((visibility(\"default\"))) int __afl_connected;"
+#ifdef __APPLE__
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/compare-transform-pass.so", obj_path);
-#endif
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
+#endif /* ^__APPLE__ */
+ // if afl is connected, we run _A times, else once.
+ "_L(__afl_connected ? _A : 1); })");
+
+ insert_param(
+ aflcc,
+ "-D__AFL_INIT()="
+ "do { static volatile const char *_A __attribute__((used,unused)); "
+ " _A = (const char*)\"" DEFER_SIG
+ "\"; "
+#ifdef __APPLE__
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"___afl_manual_init\"); "
+#else
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"__afl_manual_init\"); "
+#endif /* ^__APPLE__ */
+ "_I(); } while (0)");
- }
+}
- if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
- getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
+/*
+ Control macro def of _FORTIFY_SOURCE. It will do nothing
+ if we detect this routine has been called previously, or
+ the macro already here in these existing args.
+*/
+void add_defs_fortify(aflcc_state_t *aflcc, u8 action) {
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/split-compares-pass.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/split-compares-pass.so", obj_path);
-#endif
+ if (aflcc->have_fortify) { return; }
- }
+ switch (action) {
- // /laf
+ case 1:
+ insert_param(aflcc, "-D_FORTIFY_SOURCE=1");
+ break;
- unsetenv("AFL_LD");
- unsetenv("AFL_LD_CALLER");
+ case 2:
+ insert_param(aflcc, "-D_FORTIFY_SOURCE=2");
+ break;
- if (cmplog_mode) {
+ default: // OFF
+ insert_param(aflcc, "-U_FORTIFY_SOURCE");
+ break;
- cc_params[cc_par_cnt++] = "-fno-inline";
+ }
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/cmplog-switches-pass.so", obj_path);
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/split-switches-pass.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/cmplog-switches-pass.so", obj_path);
+ aflcc->have_fortify = 1;
- // reuse split switches from laf
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/split-switches-pass.so", obj_path);
-#endif
+}
- }
+/* Macro defs of __AFL_LEAK_CHECK, __AFL_LSAN_ON and __AFL_LSAN_OFF */
+void add_defs_lsan_ctrl(aflcc_state_t *aflcc) {
- //#if LLVM_MAJOR >= 13
- // // Use the old pass manager in LLVM 14 which the AFL++ passes still
- // use. cc_params[cc_par_cnt++] = "-flegacy-pass-manager";
- //#endif
+ insert_param(aflcc, "-includesanitizer/lsan_interface.h");
+ insert_param(
+ aflcc,
+ "-D__AFL_LEAK_CHECK()={if(__lsan_do_recoverable_leak_check() > 0) "
+ "_exit(23); }");
+ insert_param(aflcc, "-D__AFL_LSAN_OFF()=__lsan_disable();");
+ insert_param(aflcc, "-D__AFL_LSAN_ON()=__lsan_enable();");
- if (lto_mode && !have_c) {
+}
- u8 *ld_path = NULL;
- if (getenv("AFL_REAL_LD")) {
+/** Macro defs for the preprocessor -----END----- **/
- ld_path = strdup(getenv("AFL_REAL_LD"));
+/** About -fsanitize -----BEGIN----- **/
- } else {
+/* For input "-fsanitize=...", it:
- ld_path = strdup(AFL_REAL_LD);
+ 1. may have various OOB traps :) if ... doesn't contain ',' or
+ the input has bad syntax such as "-fsantiz=,"
+ 2. strips any fuzzer* in ... and writes back (may result in "-fsanitize=")
+ 3. rets 1 if exactly "fuzzer" found, otherwise rets 0
+*/
+static u8 fsanitize_fuzzer_comma(char *string) {
- }
+ u8 detect_single_fuzzer = 0;
- if (!ld_path || !*ld_path) {
+ char *p, *ptr = string + strlen("-fsanitize=");
+ // ck_alloc will check alloc failure
+ char *new = ck_alloc(strlen(string) + 1);
+ char *tmp = ck_alloc(strlen(ptr) + 1);
+ u32 count = 0, len, ende = 0;
- if (ld_path) {
+ strcpy(new, "-fsanitize=");
- // Freeing empty string
- free(ld_path);
+ do {
- }
+ p = strchr(ptr, ',');
+ if (!p) {
- ld_path = strdup("ld.lld");
+ p = ptr + strlen(ptr) + 1;
+ ende = 1;
- }
+ }
- if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
-#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
- cc_params[cc_par_cnt++] = alloc_printf("--ld-path=%s", ld_path);
-#else
- cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", ld_path);
-#endif
- free(ld_path);
+ len = p - ptr;
+ if (len) {
-#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 15
- // The NewPM implementation only works fully since LLVM 15.
- cc_params[cc_par_cnt++] = alloc_printf(
- "-Wl,--load-pass-plugin=%s/SanitizerCoverageLTO.so", obj_path);
-#elif defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
- cc_params[cc_par_cnt++] = "-Wl,--lto-legacy-pass-manager";
- cc_params[cc_par_cnt++] =
- alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-fno-experimental-new-pass-manager";
- cc_params[cc_par_cnt++] =
- alloc_printf("-Wl,-mllvm=-load=%s/SanitizerCoverageLTO.so", obj_path);
-#endif
+ strncpy(tmp, ptr, len);
+ tmp[len] = 0;
+ // fprintf(stderr, "Found: %s\n", tmp);
+ ptr += len + 1;
+ if (*tmp) {
- cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
- cc_params[cc_par_cnt++] = lto_flag;
+ u32 copy = 1;
+ if (!strcmp(tmp, "fuzzer")) {
- } else {
+ detect_single_fuzzer = 1;
+ copy = 0;
- if (instrument_mode == INSTRUMENT_PCGUARD) {
+ } else if (!strncmp(tmp, "fuzzer", 6)) {
-#if LLVM_MAJOR >= 11
- #if defined __ANDROID__ || ANDROID
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
- instrument_mode = INSTRUMENT_LLVMNATIVE;
- #else
- if (have_instr_list) {
-
- if (!be_quiet)
- SAYF(
- "Using unoptimized trace-pc-guard, due usage of "
- "-fsanitize-coverage-allow/denylist, you can use "
- "AFL_LLVM_ALLOWLIST/AFL_LLMV_DENYLIST instead.\n");
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
- instrument_mode = INSTRUMENT_LLVMNATIVE;
-
- } else {
-
- #if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] = alloc_printf(
- "-fpass-plugin=%s/SanitizerCoveragePCGUARD.so", obj_path);
- #else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/SanitizerCoveragePCGUARD.so", obj_path);
- #endif
+ copy = 0;
}
- #endif
-#else
- #if LLVM_MAJOR >= 4
- if (!be_quiet)
- SAYF(
- "Using unoptimized trace-pc-guard, upgrade to llvm 10.0.1+ for "
- "enhanced version.\n");
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
- instrument_mode = INSTRUMENT_LLVMNATIVE;
- #else
- FATAL("pcguard instrumentation requires llvm 4.0.1+");
- #endif
-#endif
+ if (copy) {
- } else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
+ if (count) { strcat(new, ","); }
+ strcat(new, tmp);
+ ++count;
-#if LLVM_MAJOR >= 4
- if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
+ }
- #if LLVM_MAJOR >= 6
- cc_params[cc_par_cnt++] =
- "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table";
- #else
- FATAL("pcguard instrumentation with pc-table requires llvm 6.0.1+");
- #endif
+ }
- } else {
+ } else {
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+ ptr++;
- }
+ }
-#else
- FATAL("pcguard instrumentation requires llvm 4.0.1+");
-#endif
+ } while (!ende);
- } else {
+ strcpy(string, new);
-#if LLVM_MAJOR >= 11 /* use new pass manager */
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/afl-llvm-pass.so", obj_path);
-#else
+ ck_free(tmp);
+ ck_free(new);
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-pass.so", obj_path);
-#endif
+ return detect_single_fuzzer;
- }
+}
- }
+/*
+ Parse and process possible -fsanitize related args, return PARAM_MISS
+ if nothing matched. We have 3 main tasks here for these args:
+ - Check which one of those sanitizers present here.
+ - Check if libfuzzer present. We need to block the request of enable
+ libfuzzer, and link harness with our libAFLDriver.a later.
+ - Check if SanCov allow/denylist options present. We need to try switching
+ to LLVMNATIVE instead of using our optimized PCGUARD anyway. If we
+ can't make it finally for various reasons, just drop these options.
+*/
+param_st parse_fsanitize(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
+
+ param_st final_ = PARAM_MISS;
+
+// MACRO START
+#define HAVE_SANITIZER_SCAN_KEEP(v, k) \
+ do { \
+ \
+ if (strstr(cur_argv, "=" STRINGIFY(k)) || \
+ strstr(cur_argv, "," STRINGIFY(k))) { \
+ \
+ if (scan) { \
+ \
+ aflcc->have_##v = 1; \
+ final_ = PARAM_SCAN; \
+ \
+ } else { \
+ \
+ final_ = PARAM_KEEP; \
+ \
+ } \
+ \
+ } \
+ \
+ } while (0)
+
+ // MACRO END
+
+ if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize="))) {
+
+ HAVE_SANITIZER_SCAN_KEEP(asan, address);
+ HAVE_SANITIZER_SCAN_KEEP(msan, memory);
+ HAVE_SANITIZER_SCAN_KEEP(ubsan, undefined);
+ HAVE_SANITIZER_SCAN_KEEP(tsan, thread);
+ HAVE_SANITIZER_SCAN_KEEP(lsan, leak);
+ HAVE_SANITIZER_SCAN_KEEP(cfisan, cfi);
- if (cmplog_mode) {
+ }
-#if LLVM_MAJOR >= 11
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] = alloc_printf(
- "-fpass-plugin=%s/cmplog-instructions-pass.so", obj_path);
- #if LLVM_MAJOR < 16
- cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
- #endif
- cc_params[cc_par_cnt++] =
- alloc_printf("-fpass-plugin=%s/cmplog-routines-pass.so", obj_path);
-#else
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/cmplog-instructions-pass.so", obj_path);
-
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] = "-load";
- cc_params[cc_par_cnt++] = "-Xclang";
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/cmplog-routines-pass.so", obj_path);
-#endif
+#undef HAVE_SANITIZER_SCAN_KEEP
+
+ // We can't use a "else if" there, because some of the following
+ // matching rules overlap with those in the if-statement above.
+ if (!strcmp(cur_argv, "-fsanitize=fuzzer")) {
+
+ if (scan) {
+
+ aflcc->need_aflpplib = 1;
+ final_ = PARAM_SCAN;
+
+ } else {
+
+ final_ = PARAM_DROP;
}
- // cc_params[cc_par_cnt++] = "-Qunused-arguments";
+ } else if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize=")) &&
+
+ strchr(cur_argv, ',') &&
+ !strstr(cur_argv, "=,")) { // avoid OOB errors
+
+ if (scan) {
- if (lto_mode && argc > 1) {
+ u8 *cur_argv_ = ck_strdup(cur_argv);
- u32 idx;
- for (idx = 1; idx < argc; idx++) {
+ if (fsanitize_fuzzer_comma(cur_argv_)) {
- if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+ aflcc->need_aflpplib = 1;
+ final_ = PARAM_SCAN;
}
- }
+ ck_free(cur_argv_);
- }
+ } else {
- /* Inspect the command line parameters. */
+ fsanitize_fuzzer_comma(cur_argv);
+ if (!cur_argv || strlen(cur_argv) <= strlen("-fsanitize="))
+ final_ = PARAM_DROP; // this means it only has "fuzzer" previously.
- process_params(argc, argv);
+ }
- if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; }
+ } else if (!strncmp(cur_argv, "-fsanitize-coverage-", 20) &&
- // in case LLVM is installed not via a package manager or "make install"
- // e.g. compiled download or compiled from github then its ./lib directory
- // might not be in the search path. Add it if so.
- u8 *libdir = strdup(LLVM_LIBDIR);
- if (plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
- strncmp(libdir, "/lib", 4)) {
+ strstr(cur_argv, "list=")) {
- cc_params[cc_par_cnt++] = "-Wl,-rpath";
- cc_params[cc_par_cnt++] = libdir;
+ if (scan) {
- } else {
+ aflcc->have_instr_list = 1;
+ final_ = PARAM_SCAN;
- free(libdir);
+ } else {
- }
+ if (aflcc->instrument_mode != INSTRUMENT_LLVMNATIVE) {
- if (getenv("AFL_HARDEN")) {
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur_argv); }
+ final_ = PARAM_DROP;
+
+ } else {
- cc_params[cc_par_cnt++] = "-fstack-protector-all";
+ final_ = PARAM_KEEP;
- if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
+ }
+
+ }
}
- if (!asan_set) {
+ if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
- if (getenv("AFL_USE_ASAN")) {
+ return final_;
- if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
+}
- if (getenv("AFL_HARDEN"))
- FATAL("ASAN and AFL_HARDEN are mutually exclusive");
+/*
+ Add params for sanitizers. Here we need to consider:
+ - Use static runtime for asan, as much as possible.
+ - ASAN, MSAN, AFL_HARDEN are mutually exclusive.
+ - Add options if not found there, on request of AFL_USE_ASAN, AFL_USE_MSAN,
+ etc.
+ - Update have_* so that functions called after this can have correct context.
+ However this also means any functions called before should NOT depend on
+ these have_*, otherwise they may not work as expected.
+*/
+void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
- cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
- cc_params[cc_par_cnt++] = "-fsanitize=address";
+ if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
- } else if (getenv("AFL_USE_MSAN")) {
+ if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
+ FATAL("ASAN and MSAN are mutually exclusive");
- if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
+ if (getenv("AFL_HARDEN"))
+ FATAL("ASAN and AFL_HARDEN are mutually exclusive");
- if (getenv("AFL_HARDEN"))
- FATAL("MSAN and AFL_HARDEN are mutually exclusive");
+ if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
- cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
- cc_params[cc_par_cnt++] = "-fsanitize=memory";
+ insert_param(aflcc, "-static-libasan");
}
- }
+ add_defs_fortify(aflcc, 0);
+ if (!aflcc->have_asan) {
- if (getenv("AFL_USE_UBSAN")) {
+ insert_param(aflcc, "-fsanitize=address");
+ insert_param(aflcc, "-fno-common");
- cc_params[cc_par_cnt++] = "-fsanitize=undefined";
- cc_params[cc_par_cnt++] = "-fsanitize-undefined-trap-on-error";
- cc_params[cc_par_cnt++] = "-fno-sanitize-recover=all";
- cc_params[cc_par_cnt++] = "-fno-omit-frame-pointer";
+ }
- }
+ aflcc->have_asan = 1;
+
+ } else if (getenv("AFL_USE_MSAN") || aflcc->have_msan) {
+
+ if (getenv("AFL_USE_ASAN") || aflcc->have_asan)
+ FATAL("ASAN and MSAN are mutually exclusive");
- if (getenv("AFL_USE_TSAN")) {
+ if (getenv("AFL_HARDEN"))
+ FATAL("MSAN and AFL_HARDEN are mutually exclusive");
- cc_params[cc_par_cnt++] = "-fsanitize=thread";
- cc_params[cc_par_cnt++] = "-fno-omit-frame-pointer";
+ add_defs_fortify(aflcc, 0);
+ if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
+ aflcc->have_msan = 1;
}
- if (getenv("AFL_USE_LSAN")) {
+ if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
- 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()={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();";
+ if (!aflcc->have_ubsan) {
- }
+ insert_param(aflcc, "-fsanitize=undefined");
+ insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
+ insert_param(aflcc, "-fno-sanitize-recover=all");
- if (getenv("AFL_USE_CFISAN")) {
+ }
- if (compiler_mode == GCC_PLUGIN || compiler_mode == GCC) {
+ if (!aflcc->have_fp) {
- cc_params[cc_par_cnt++] = "-fcf-protection=full";
+ insert_param(aflcc, "-fno-omit-frame-pointer");
+ aflcc->have_fp = 1;
- } else {
+ }
- if (!lto_mode) {
+ aflcc->have_ubsan = 1;
- uint32_t i = 0, found = 0;
- while (envp[i] != NULL && !found)
- if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
- if (!found) cc_params[cc_par_cnt++] = "-flto";
+ }
- }
+ if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
+
+ if (!aflcc->have_fp) {
- cc_params[cc_par_cnt++] = "-fsanitize=cfi";
- cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+ insert_param(aflcc, "-fno-omit-frame-pointer");
+ aflcc->have_fp = 1;
}
+ if (!aflcc->have_tsan) { insert_param(aflcc, "-fsanitize=thread"); }
+ aflcc->have_tsan = 1;
+
}
- if (!getenv("AFL_DONT_OPTIMIZE")) {
+ if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
- cc_params[cc_par_cnt++] = "-g";
- if (!have_o) cc_params[cc_par_cnt++] = "-O3";
- if (!have_unroll) cc_params[cc_par_cnt++] = "-funroll-loops";
- // if (strlen(march_opt) > 1 && march_opt[0] == '-')
- // cc_params[cc_par_cnt++] = march_opt;
+ insert_param(aflcc, "-fsanitize=leak");
+ add_defs_lsan_ctrl(aflcc);
+ aflcc->have_lsan = 1;
}
- if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
- getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_ALL") ||
- lto_mode) {
+ if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
- cc_params[cc_par_cnt++] = "-fno-builtin-strcmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-strncmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-strcasecmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-strncasecmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-memcmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-bcmp";
- cc_params[cc_par_cnt++] = "-fno-builtin-strstr";
- cc_params[cc_par_cnt++] = "-fno-builtin-strcasestr";
+ if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
- }
+ if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
-#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
- if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
-#endif
+ } else {
- cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
- cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
+ if (!aflcc->lto_mode && !aflcc->have_flto) {
- /* As documented in instrumentation/README.persistent_mode.md, deferred
- forkserver initialization and persistent mode are not available in afl-gcc
- and afl-clang. */
- if (compiler_mode != GCC && compiler_mode != CLANG) {
+ uint32_t i = 0, found = 0;
+ while (envp[i] != NULL && !found) {
- cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
+ if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
- /* When the user tries to use persistent or deferred forkserver modes by
- appending a single line to the program, we want to reliably inject a
- signature into the binary (to be picked up by afl-fuzz) and we want
- to call a function from the runtime .o file. This is unnecessarily
- painful for three reasons:
+ }
- 1) We need to convince the compiler not to optimize out the signature.
- This is done with __attribute__((used)).
+ if (!found) { insert_param(aflcc, "-flto"); }
+ aflcc->have_flto = 1;
- 2) We need to convince the linker, when called with -Wl,--gc-sections,
- not to do the same. This is done by forcing an assignment to a
- 'volatile' pointer.
+ }
- 3) We need to declare __afl_persistent_loop() in the global namespace,
- but doing this within a method in a class is hard - :: and extern "C"
- are forbidden and __attribute__((alias(...))) doesn't work. Hence the
- __asm__ aliasing trick.
+ if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
- */
+ if (!aflcc->have_hidden) {
- cc_params[cc_par_cnt++] =
- "-D__AFL_FUZZ_INIT()="
- "int __afl_sharedmem_fuzzing = 1;"
- "extern unsigned int *__afl_fuzz_len;"
- "extern unsigned char *__afl_fuzz_ptr;"
- "unsigned char __afl_fuzz_alt[1048576];"
- "unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;";
+ insert_param(aflcc, "-fvisibility=hidden");
+ aflcc->have_hidden = 1;
- }
+ }
- if (plusplus_mode) {
+ aflcc->have_cfisan = 1;
- cc_params[cc_par_cnt++] =
- "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
- "extern \"C\" void __afl_coverage_discard();"
- "extern \"C\" void __afl_coverage_skip();"
- "extern \"C\" void __afl_coverage_on();"
- "extern \"C\" void __afl_coverage_off();";
+ }
- } else {
+ }
- cc_params[cc_par_cnt++] =
- "-D__AFL_COVERAGE()=int __afl_selective_coverage = 1;"
- "void __afl_coverage_discard();"
- "void __afl_coverage_skip();"
- "void __afl_coverage_on();"
- "void __afl_coverage_off();";
+}
- }
+/* Add params to enable LLVM SanCov, the native PCGUARD */
+void add_native_pcguard(aflcc_state_t *aflcc) {
- cc_params[cc_par_cnt++] =
- "-D__AFL_COVERAGE_START_OFF()=int __afl_selective_coverage_start_off = "
- "1;";
- cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_ON()=__afl_coverage_on()";
- cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_OFF()=__afl_coverage_off()";
- cc_params[cc_par_cnt++] =
- "-D__AFL_COVERAGE_DISCARD()=__afl_coverage_discard()";
- cc_params[cc_par_cnt++] = "-D__AFL_COVERAGE_SKIP()=__afl_coverage_skip()";
- cc_params[cc_par_cnt++] =
- "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
- "__afl_fuzz_alt_ptr)";
- cc_params[cc_par_cnt++] =
- "-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : "
- "(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
- "? 0 : *__afl_fuzz_len)";
+ /* If there is a rust ASan runtime on the command line, it is likely we're
+ * linking from rust and adding native flags requiring the sanitizer runtime
+ * will trigger native clang to add yet another runtime, causing linker
+ * errors. For now we shouldn't add instrumentation here, we're linking
+ * anyway.
+ */
+ if (aflcc->have_rust_asanrt) { return; }
- if (compiler_mode != GCC && compiler_mode != CLANG) {
+ /* If llvm-config doesn't figure out LLVM_MAJOR, just
+ go on anyway and let compiler complain if doesn't work. */
- cc_params[cc_par_cnt++] =
- "-D__AFL_LOOP(_A)="
- "({ static volatile const char *_B __attribute__((used,unused)); "
- " _B = (const char*)\"" PERSIST_SIG
- "\"; "
- "extern int __afl_connected;"
-#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
-#else
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
-#endif /* ^__APPLE__ */
- // if afl is connected, we run _A times, else once.
- "_L(__afl_connected ? _A : 1); })";
-
- cc_params[cc_par_cnt++] =
- "-D__AFL_INIT()="
- "do { static volatile const char *_A __attribute__((used,unused)); "
- " _A = (const char*)\"" DEFER_SIG
- "\"; "
-#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"___afl_manual_init\"); "
+#if LLVM_MAJOR > 0 && LLVM_MAJOR < 6
+ FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
#else
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"__afl_manual_init\"); "
-#endif /* ^__APPLE__ */
- "_I(); } while (0)";
+ #if LLVM_MAJOR == 0
+ WARNF(
+ "pcguard instrumentation with pc-table requires LLVM 6.0.1+"
+ " otherwise the compiler will fail");
+ #endif
+ if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
- }
+ insert_param(aflcc,
+ "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
- if (x_set) {
+ } else {
- cc_params[cc_par_cnt++] = "-x";
- cc_params[cc_par_cnt++] = "none";
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard,pc-table");
}
- // prevent unnecessary build errors
- if (compiler_mode != GCC_PLUGIN && compiler_mode != GCC) {
+#endif
- cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+}
- }
+/*
+ Add params to launch our optimized PCGUARD on request.
+ It will fallback to use the native PCGUARD in some cases. If so, plz
+ bear in mind that instrument_mode will be set to INSTRUMENT_LLVMNATIVE.
+*/
+void add_optimized_pcguard(aflcc_state_t *aflcc) {
- if (preprocessor_only || have_c || !non_dash) {
+#if LLVM_MAJOR >= 13
+ #if defined __ANDROID__ || ANDROID
- /* In the preprocessor_only case (-E), we are not actually compiling at
- all but requesting the compiler to output preprocessed sources only.
- We must not add the runtime in this case because the compiler will
- simply output its binary content back on stdout, breaking any build
- systems that rely on a separate source preprocessing step. */
- cc_params[cc_par_cnt] = NULL;
- return;
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- }
+ #else
-#ifndef __ANDROID__
+ if (aflcc->have_instr_list) {
- if (compiler_mode != GCC && compiler_mode != CLANG) {
+ if (!be_quiet)
+ SAYF(
+ "Using unoptimized trace-pc-guard, due usage of "
+ "-fsanitize-coverage-allow/denylist, you can use "
+ "AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST instead.\n");
- switch (bit_mode) {
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- case 0:
- if (!shared_linking && !partial_linking)
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-compiler-rt.o", obj_path);
- if (lto_mode)
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
- break;
+ } else {
- case 32:
- if (!shared_linking && !partial_linking) {
+ /* Since LLVM_MAJOR >= 13 we use new pass manager */
+ #if LLVM_MAJOR < 16
+ insert_param(aflcc, "-fexperimental-new-pass-manager");
+ #endif
+ insert_object(aflcc, "SanitizerCoveragePCGUARD.so", "-fpass-plugin=%s", 0);
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
- if (access(cc_params[cc_par_cnt - 1], R_OK))
- FATAL("-m32 is not supported by your compiler");
+ }
- }
+ #endif // defined __ANDROID__ || ANDROID
+#else // LLVM_MAJOR < 13
+ #if LLVM_MAJOR >= 4
+
+ if (!be_quiet)
+ SAYF(
+ "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ for "
+ "enhanced version.\n");
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- if (lto_mode) {
+ #else
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path);
- if (access(cc_params[cc_par_cnt - 1], R_OK))
- FATAL("-m32 is not supported by your compiler");
+ FATAL("pcguard instrumentation requires LLVM 4.0.1+");
- }
+ #endif
+#endif
- break;
+}
- case 64:
- if (!shared_linking && !partial_linking) {
+/** About -fsanitize -----END----- **/
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
- if (access(cc_params[cc_par_cnt - 1], R_OK))
- FATAL("-m64 is not supported by your compiler");
+/** Linking behaviors -----BEGIN----- **/
- }
+/*
+ Parse and process possible linking stage related args,
+ return PARAM_MISS if nothing matched.
+*/
+param_st parse_linking_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan,
+ u8 *skip_next, char **argv) {
- if (lto_mode) {
+ if (aflcc->lto_mode && !strncmp(cur_argv, "-flto=thin", 10)) {
- cc_params[cc_par_cnt++] =
- alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path);
- if (access(cc_params[cc_par_cnt - 1], R_OK))
- FATAL("-m64 is not supported by your compiler");
+ FATAL(
+ "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
+ "use afl-clang-fast!");
- }
+ }
- break;
+ param_st final_ = PARAM_MISS;
- }
+ if (!strcmp(cur_argv, "-shared") || !strcmp(cur_argv, "-dynamiclib")) {
- #if !defined(__APPLE__) && !defined(__sun)
- if (!shared_linking && !partial_linking)
- cc_params[cc_par_cnt++] =
- alloc_printf("-Wl,--dynamic-list=%s/dynamic_list.txt", obj_path);
- #endif
+ if (scan) {
- #if defined(__APPLE__)
- if (shared_linking || partial_linking) {
+ aflcc->shared_linking = 1;
+ final_ = PARAM_SCAN;
- cc_params[cc_par_cnt++] = "-Wl,-U";
- cc_params[cc_par_cnt++] = "-Wl,___afl_area_ptr";
- cc_params[cc_par_cnt++] = "-Wl,-U";
- cc_params[cc_par_cnt++] = "-Wl,___sanitizer_cov_trace_pc_guard_init";
+ } else {
+
+ final_ = PARAM_KEEP;
}
- #endif
+ } else if (!strcmp(cur_argv, "-Wl,-r") || !strcmp(cur_argv, "-Wl,-i") ||
- }
+ !strcmp(cur_argv, "-Wl,--relocatable") ||
+ !strcmp(cur_argv, "-r") || !strcmp(cur_argv, "--relocatable")) {
- #if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
- cc_params[cc_par_cnt++] = "-lrt";
- #endif
+ if (scan) {
-#endif
+ aflcc->partial_linking = 1;
+ final_ = PARAM_SCAN;
- cc_params[cc_par_cnt] = NULL;
+ } else {
-}
+ final_ = PARAM_KEEP;
-/* Main entry point */
+ }
-int main(int argc, char **argv, char **envp) {
+ } else if (!strncmp(cur_argv, "-fuse-ld=", 9) ||
- int i;
- char *callname = argv[0], *ptr = NULL;
+ !strncmp(cur_argv, "--ld-path=", 10)) {
- if (getenv("AFL_DEBUG")) {
+ if (scan) {
- debug = 1;
- if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
+ final_ = PARAM_SCAN;
- } else if (getenv("AFL_QUIET"))
+ } else {
- be_quiet = 1;
+ if (aflcc->lto_mode)
+ final_ = PARAM_DROP;
+ else
+ final_ = PARAM_KEEP;
- if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
- getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
- getenv("AFL_LLVM_BLOCKLIST")) {
+ }
- have_instr_env = 1;
+ } else if (!strcmp(cur_argv, "-Wl,-z,defs") ||
- }
+ !strcmp(cur_argv, "-Wl,--no-undefined") ||
+ !strcmp(cur_argv, "-Wl,-no-undefined") ||
+ !strcmp(cur_argv, "--no-undefined") ||
+ strstr(cur_argv, "afl-compiler-rt") ||
+ strstr(cur_argv, "afl-llvm-rt")) {
- if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
+ if (scan) {
- passthrough = 1;
- if (!debug) { be_quiet = 1; }
+ final_ = PARAM_SCAN;
- }
+ } else {
- if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
- argvnull = (u8 *)argv[0];
- check_environment_vars(envp);
+ final_ = PARAM_DROP;
- if ((ptr = find_object("as", argv[0])) != NULL) {
+ }
- have_gcc = 1;
- ck_free(ptr);
+ } else if (!strcmp(cur_argv, "-z") || !strcmp(cur_argv, "-Wl,-z")) {
- }
+ u8 *param = *(argv + 1);
+ if (param && (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs"))) {
-#if (LLVM_MAJOR >= 3)
+ *skip_next = 1;
- if ((ptr = find_object("SanitizerCoverageLTO.so", argv[0])) != NULL) {
+ if (scan) {
- have_lto = 1;
- ck_free(ptr);
+ final_ = PARAM_SCAN;
- }
+ } else {
- if ((ptr = find_object("cmplog-routines-pass.so", argv[0])) != NULL) {
+ final_ = PARAM_DROP;
- have_llvm = 1;
- ck_free(ptr);
+ }
+
+ }
}
-#endif
+ // Try to warn user for some unsupported cases
+ if (scan && final_ == PARAM_MISS) {
-#ifdef __ANDROID__
- have_llvm = 1;
-#endif
+ u8 *ptr_ = NULL;
- if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) {
+ if (!strcmp(cur_argv, "-Xlinker") && (ptr_ = *(argv + 1))) {
- have_gcc_plugin = 1;
- ck_free(ptr);
+ if (!strcmp(ptr_, "defs")) {
- }
+ WARNF("'-Xlinker' 'defs' detected. This may result in a bad link.");
-#if (LLVM_MAJOR >= 3)
+ } else if (strstr(ptr_, "-no-undefined")) {
- if (strncmp(callname, "afl-clang-fast", 14) == 0) {
+ WARNF(
+ "'-Xlinker' '%s' detected. The latter option may be dropped and "
+ "result in a bad link.",
+ ptr_);
- compiler_mode = LLVM;
+ }
- } else if (strncmp(callname, "afl-clang-lto", 13) == 0 ||
+ } else if (!strncmp(cur_argv, "-Wl,", 4) &&
- strncmp(callname, "afl-lto", 7) == 0) {
+ (u8 *)strrchr(cur_argv, ',') != (cur_argv + 3)) {
- compiler_mode = LTO;
+ ptr_ = cur_argv + 4;
- } else
+ if (strstr(ptr_, "-shared") || strstr(ptr_, "-dynamiclib")) {
-#endif
- if (strncmp(callname, "afl-gcc-fast", 12) == 0 ||
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may break shared "
+ "linking.",
+ ptr_);
- strncmp(callname, "afl-g++-fast", 12) == 0) {
+ }
- compiler_mode = GCC_PLUGIN;
+ if (strstr(ptr_, "-r,") || strstr(ptr_, "-i,") || strstr(ptr_, ",-r") ||
+ strstr(ptr_, ",-i") || strstr(ptr_, "--relocatable")) {
- } else if (strncmp(callname, "afl-gcc", 7) == 0 ||
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may break partial "
+ "linking.",
+ ptr_);
- strncmp(callname, "afl-g++", 7) == 0) {
+ }
- compiler_mode = GCC;
+ if (strstr(ptr_, "defs") || strstr(ptr_, "no-undefined")) {
- } else if (strcmp(callname, "afl-clang") == 0 ||
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may enable report "
+ "unresolved symbol references and result in a bad link.",
+ ptr_);
- strcmp(callname, "afl-clang++") == 0) {
+ }
- compiler_mode = CLANG;
+ }
}
- if ((ptr = getenv("AFL_CC_COMPILER"))) {
+ if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
- if (compiler_mode) {
+ return final_;
- if (!be_quiet) {
+}
- WARNF(
- "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
- "selected by command line parameter or symlink, ignoring the "
- "environment variable!");
+/* Add params to specify the linker used in LTO */
+void add_lto_linker(aflcc_state_t *aflcc) {
- }
+ unsetenv("AFL_LD");
+ unsetenv("AFL_LD_CALLER");
- } else {
+ u8 *ld_path = NULL;
+ if (getenv("AFL_REAL_LD")) {
- if (strncasecmp(ptr, "LTO", 3) == 0) {
+ ld_path = strdup(getenv("AFL_REAL_LD"));
- compiler_mode = LTO;
+ } else {
- } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+ ld_path = strdup(AFL_REAL_LD);
- compiler_mode = LLVM;
+ }
- } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+ if (!ld_path || !*ld_path) {
- strncasecmp(ptr, "GCC-P", 5) == 0 ||
- strncasecmp(ptr, "GCCP", 4) == 0) {
+ if (ld_path) {
- compiler_mode = GCC_PLUGIN;
+ // Freeing empty string
+ free(ld_path);
- } else if (strcasecmp(ptr, "GCC") == 0) {
+ }
- compiler_mode = GCC;
+ ld_path = strdup("ld.lld");
- } else
+ }
- FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
+ if (!ld_path) { PFATAL("Could not allocate mem for ld_path"); }
+#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 12
+ insert_param(aflcc, alloc_printf("--ld-path=%s", ld_path));
+#else
+ insert_param(aflcc, alloc_printf("-fuse-ld=%s", ld_path));
+#endif
+ free(ld_path);
- }
+}
- }
+/* Add params to launch SanitizerCoverageLTO.so when linking */
+void add_lto_passes(aflcc_state_t *aflcc) {
- if (strcmp(callname, "afl-clang") == 0 ||
- strcmp(callname, "afl-clang++") == 0) {
+#if defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 15
+ // The NewPM implementation only works fully since LLVM 15.
+ insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,--load-pass-plugin=%s",
+ 0);
+#elif defined(AFL_CLANG_LDPATH) && LLVM_MAJOR >= 13
+ insert_param(aflcc, "-Wl,--lto-legacy-pass-manager");
+ insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
+#else
+ insert_param(aflcc, "-fno-experimental-new-pass-manager");
+ insert_object(aflcc, "SanitizerCoverageLTO.so", "-Wl,-mllvm=-load=%s", 0);
+#endif
- clang_mode = 1;
- compiler_mode = CLANG;
+ insert_param(aflcc, "-Wl,--allow-multiple-definition");
- if (strcmp(callname, "afl-clang++") == 0) { plusplus_mode = 1; }
+}
- }
+/* Add params to link with libAFLDriver.a on request */
+static void add_aflpplib(aflcc_state_t *aflcc) {
- for (i = 1; i < argc; i++) {
+ if (!aflcc->need_aflpplib) return;
- if (strncmp(argv[i], "--afl", 5) == 0) {
+ u8 *afllib = find_object(aflcc, "libAFLDriver.a");
- if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
+ if (!be_quiet) {
- passthrough = 1;
- argv[i] = "-g"; // we have to overwrite it, -g is always good
- continue;
+ OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
- }
+ }
- if (compiler_mode && !be_quiet) {
+ if (!afllib) {
- WARNF(
- "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
- "symlink compiler selection!");
+ if (!be_quiet) {
- }
+ WARNF(
+ "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
+ "the flags - this will fail!");
- ptr = argv[i];
- ptr += 5;
- while (*ptr == '-')
- ptr++;
+ }
- if (strncasecmp(ptr, "LTO", 3) == 0) {
+ } else {
- compiler_mode = LTO;
+ insert_param(aflcc, afllib);
- } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+#ifdef __APPLE__
+ insert_param(aflcc, "-Wl,-undefined");
+ insert_param(aflcc, "dynamic_lookup");
+#endif
- compiler_mode = LLVM;
+ }
- } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
+}
- strncasecmp(ptr, "PC-GUARD", 8) == 0) {
+/* Add params to link with runtimes depended by our instrumentation */
+void add_runtime(aflcc_state_t *aflcc) {
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_PCGUARD;
+ if (aflcc->preprocessor_only || aflcc->have_c || !aflcc->non_dash) {
- } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
+ /* In the preprocessor_only case (-E), we are not actually compiling at
+ all but requesting the compiler to output preprocessed sources only.
+ We must not add the runtime in this case because the compiler will
+ simply output its binary content back on stdout, breaking any build
+ systems that rely on a separate source preprocessing step. */
+ return;
- strcasecmp(ptr, "CFG") == 0) {
+ }
- FATAL(
- "InsTrim instrumentation was removed. Use a modern LLVM and "
- "PCGUARD (default in afl-cc).\n");
+ if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC &&
+ !getenv("AFL_LLVM_NO_RPATH")) {
- } else if (strcasecmp(ptr, "AFL") == 0 ||
+ // in case LLVM is installed not via a package manager or "make install"
+ // e.g. compiled download or compiled from github then its ./lib directory
+ // might not be in the search path. Add it if so.
+ const char *libdir = LLVM_LIBDIR;
+ if (aflcc->plusplus_mode && strlen(libdir) && strncmp(libdir, "/usr", 4) &&
+ strncmp(libdir, "/lib", 4)) {
- strcasecmp(ptr, "CLASSIC") == 0) {
+#ifdef __APPLE__
+ u8 *libdir_opt = strdup("-Wl,-rpath," LLVM_LIBDIR);
+#else
+ u8 *libdir_opt = strdup("-Wl,-rpath=" LLVM_LIBDIR);
+#endif
+ insert_param(aflcc, libdir_opt);
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_CLASSIC;
+ }
- } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
+ }
- strcasecmp(ptr, "NATIVE") == 0 ||
- strcasecmp(ptr, "LLVM-NATIVE") == 0) {
+#ifndef __ANDROID__
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_LLVMNATIVE;
+ #define M32_ERR_MSG "-m32 is not supported by your compiler"
+ #define M64_ERR_MSG "-m64 is not supported by your compiler"
- } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+ if (aflcc->compiler_mode != GCC && aflcc->compiler_mode != CLANG) {
- strncasecmp(ptr, "GCC-P", 5) == 0 ||
- strncasecmp(ptr, "GCCP", 4) == 0) {
+ switch (aflcc->bit_mode) {
- compiler_mode = GCC_PLUGIN;
+ case 0:
+ if (!aflcc->shared_linking && !aflcc->partial_linking)
+ insert_object(aflcc, "afl-compiler-rt.o", 0, 0);
+ if (aflcc->lto_mode) insert_object(aflcc, "afl-llvm-rt-lto.o", 0, 0);
+ break;
- } else if (strcasecmp(ptr, "GCC") == 0) {
+ case 32:
+ if (!aflcc->shared_linking && !aflcc->partial_linking)
+ insert_object(aflcc, "afl-compiler-rt-32.o", 0, M32_ERR_MSG);
+ if (aflcc->lto_mode)
+ insert_object(aflcc, "afl-llvm-rt-lto-32.o", 0, M32_ERR_MSG);
+ break;
- compiler_mode = GCC;
+ case 64:
+ if (!aflcc->shared_linking && !aflcc->partial_linking)
+ insert_object(aflcc, "afl-compiler-rt-64.o", 0, M64_ERR_MSG);
+ if (aflcc->lto_mode)
+ insert_object(aflcc, "afl-llvm-rt-lto-64.o", 0, M64_ERR_MSG);
+ break;
- } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
+ }
- compiler_mode = CLANG;
+ #if __AFL_CODE_COVERAGE
+ // Required for dladdr used in afl-compiler-rt.o
+ insert_param(aflcc, "-ldl");
+ #endif
- } else
+ #if !defined(__APPLE__) && !defined(__sun)
+ if (!aflcc->shared_linking && !aflcc->partial_linking)
+ insert_object(aflcc, "dynamic_list.txt", "-Wl,--dynamic-list=%s", 0);
+ #endif
- FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
+ #if defined(__APPLE__)
+ if (aflcc->shared_linking || aflcc->partial_linking) {
+
+ insert_param(aflcc, "-Wl,-U");
+ insert_param(aflcc, "-Wl,___afl_area_ptr");
+ insert_param(aflcc, "-Wl,-U");
+ insert_param(aflcc, "-Wl,___sanitizer_cov_trace_pc_guard_init");
}
+ #endif
+
}
- if (strlen(callname) > 2 &&
- (strncmp(callname + strlen(callname) - 2, "++", 2) == 0 ||
- strstr(callname, "-g++") != NULL))
- plusplus_mode = 1;
+#endif
- if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
- getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
+ add_aflpplib(aflcc);
- if (instrument_mode == 0)
- instrument_mode = INSTRUMENT_PCGUARD;
- else if (instrument_mode != INSTRUMENT_PCGUARD)
- FATAL("you cannot set AFL_LLVM_INSTRUMENT and AFL_TRACE_PC together");
+#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
+ insert_param(aflcc, "-Wl,-lrt");
+#endif
- }
+}
- if (have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
+/** Linking behaviors -----END----- **/
- WARNF(
- "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
- "for file matching, only function matching!");
+/** Miscellaneous routines -----BEGIN----- **/
- }
+/*
+ Add params to make compiler driver use our afl-as
+ as assembler, required by the vanilla instrumentation.
+*/
+void add_assembler(aflcc_state_t *aflcc) {
- if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
- getenv("INSTRIM_LIB")) {
+ u8 *afl_as = find_object(aflcc, "afl-as");
- FATAL(
- "InsTrim instrumentation was removed. Use a modern LLVM and PCGUARD "
- "(default in afl-cc).\n");
+ if (!afl_as) FATAL("Cannot find 'afl-as'.");
- }
+ u8 *slash = strrchr(afl_as, '/');
+ if (slash) *slash = 0;
- if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
- if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ // Search for 'as' may be unreliable in some cases (see #2058)
+ // so use 'afl-as' instead, because 'as' is usually a symbolic link,
+ // or can be a renamed copy of 'afl-as' created in the same dir.
+ // Now we should verify if the compiler can find the 'as' we need.
- if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+#define AFL_AS_ERR "(should be a symlink or copy of 'afl-as')"
- instrument_opt_mode |= INSTRUMENT_OPT_NGRAM;
- ngram_size = atoi(getenv("AFL_LLVM_NGRAM_SIZE"));
- if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
- FATAL(
- "NGRAM instrumentation mode must be between 2 and NGRAM_SIZE_MAX "
- "(%u)",
- NGRAM_SIZE_MAX);
+ u8 *afl_as_dup = alloc_printf("%s/as", afl_as);
- }
+ int fd = open(afl_as_dup, O_RDONLY);
+ if (fd < 0) { PFATAL("Unable to open '%s' " AFL_AS_ERR, afl_as_dup); }
- if (getenv("AFL_LLVM_CTX_K")) {
+ struct stat st;
+ if (fstat(fd, &st) < 0) {
- ctx_k = atoi(getenv("AFL_LLVM_CTX_K"));
- if (ctx_k < 1 || ctx_k > CTX_MAX_K)
- FATAL("K-CTX instrumentation mode must be between 1 and CTX_MAX_K (%u)",
- CTX_MAX_K);
- if (ctx_k == 1) {
+ PFATAL("Unable to fstat '%s' " AFL_AS_ERR, afl_as_dup);
- setenv("AFL_LLVM_CALLER", "1", 1);
- unsetenv("AFL_LLVM_CTX_K");
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ }
- } else {
+ u32 f_len = st.st_size;
- instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
+ u8 *f_data = mmap(0, f_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (f_data == MAP_FAILED) {
- }
+ PFATAL("Unable to mmap file '%s' " AFL_AS_ERR, afl_as_dup);
}
- if (getenv("AFL_LLVM_INSTRUMENT")) {
+ close(fd);
- u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
+ // "AFL_AS" is a const str passed to getenv in afl-as.c
+ if (!memmem(f_data, f_len, "AFL_AS", strlen("AFL_AS") + 1)) {
- while (ptr2) {
+ FATAL(
+ "Looks like '%s' is not a valid symlink or copy of '%s/afl-as'. "
+ "It is a prerequisite to override system-wide 'as' for "
+ "instrumentation.",
+ afl_as_dup, afl_as);
- if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
- strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
+ }
- if (instrument_mode == INSTRUMENT_LTO) {
+ if (munmap(f_data, f_len)) { PFATAL("unmap() failed"); }
- instrument_mode = INSTRUMENT_CLASSIC;
- lto_mode = 1;
+ ck_free(afl_as_dup);
- } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) {
+#undef AFL_AS_ERR
- instrument_mode = INSTRUMENT_AFL;
+ insert_param(aflcc, "-B");
+ insert_param(aflcc, afl_as);
- } else {
+ if (aflcc->compiler_mode == CLANG) insert_param(aflcc, "-no-integrated-as");
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+}
- }
+/* Add params to launch the gcc plugins for instrumentation. */
+void add_gcc_plugin(aflcc_state_t *aflcc) {
- }
+ if (aflcc->cmplog_mode) {
- if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
- strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
+ insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
+ insert_object(aflcc, "afl-gcc-cmptrs-pass.so", "-fplugin=%s", 0);
- if (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
- instrument_mode = INSTRUMENT_PCGUARD;
- else
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+ }
- }
+ insert_object(aflcc, "afl-gcc-pass.so", "-fplugin=%s", 0);
- if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
- strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0) {
+ insert_param(aflcc, "-fno-if-conversion");
+ insert_param(aflcc, "-fno-if-conversion2");
- if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE)
- instrument_mode = INSTRUMENT_LLVMNATIVE;
- else
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+}
- }
+/* Add some miscellaneous params required by our instrumentation. */
+void add_misc_params(aflcc_state_t *aflcc) {
- if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
- strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
+ if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
+ getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
+ aflcc->lto_mode) {
+
+ insert_param(aflcc, "-fno-builtin-strcmp");
+ insert_param(aflcc, "-fno-builtin-strncmp");
+ insert_param(aflcc, "-fno-builtin-strcasecmp");
+ insert_param(aflcc, "-fno-builtin-strncasecmp");
+ insert_param(aflcc, "-fno-builtin-memcmp");
+ insert_param(aflcc, "-fno-builtin-bcmp");
+ insert_param(aflcc, "-fno-builtin-strstr");
+ insert_param(aflcc, "-fno-builtin-strcasestr");
- if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) {
+ }
- instrument_mode = INSTRUMENT_LLVMNATIVE;
- instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
+ if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
- } else {
+ if (getenv("AFL_HARDEN")) {
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+ insert_param(aflcc, "-fstack-protector-all");
- }
+ if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
- }
+ }
- if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
- strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
+ if (!getenv("AFL_DONT_OPTIMIZE")) {
- FATAL(
- "InsTrim instrumentation was removed. Use a modern LLVM and "
- "PCGUARD (default in afl-cc).\n");
+ insert_param(aflcc, "-g");
+ if (!aflcc->have_o) insert_param(aflcc, "-O3");
+ if (!aflcc->have_unroll) insert_param(aflcc, "-funroll-loops");
+ // if (strlen(aflcc->march_opt) > 1 && aflcc->march_opt[0] == '-')
+ // insert_param(aflcc, aflcc->march_opt);
- }
+ }
- if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
+ if (aflcc->x_set) {
- lto_mode = 1;
- if (!instrument_mode || instrument_mode == INSTRUMENT_LTO)
- instrument_mode = INSTRUMENT_LTO;
- else
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+ insert_param(aflcc, "-x");
+ insert_param(aflcc, "none");
- }
+ }
- if (strcasecmp(ptr2, "gcc") == 0) {
+}
- if (!instrument_mode || instrument_mode == INSTRUMENT_GCC)
- instrument_mode = INSTRUMENT_GCC;
- else if (instrument_mode != INSTRUMENT_GCC)
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
- compiler_mode = GCC;
+/*
+ Parse and process a variety of args under our matching rules,
+ return PARAM_MISS if nothing matched.
+*/
+param_st parse_misc_params(aflcc_state_t *aflcc, u8 *cur_argv, u8 scan) {
- }
+ param_st final_ = PARAM_MISS;
- if (strcasecmp(ptr2, "clang") == 0) {
+// MACRO START
+#define SCAN_KEEP(dst, src) \
+ do { \
+ \
+ if (scan) { \
+ \
+ dst = src; \
+ final_ = PARAM_SCAN; \
+ \
+ } else { \
+ \
+ final_ = PARAM_KEEP; \
+ \
+ } \
+ \
+ } while (0)
- if (!instrument_mode || instrument_mode == INSTRUMENT_CLANG)
- instrument_mode = INSTRUMENT_CLANG;
- else if (instrument_mode != INSTRUMENT_CLANG)
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
- compiler_mode = CLANG;
+ // MACRO END
- }
+ if (!strncasecmp(cur_argv, "-fpic", 5)) {
- if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
- strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
- strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
+ SCAN_KEEP(aflcc->have_pic, 1);
- u8 *ptr3 = ptr2;
- while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
- ptr3++;
+ } else if (!strcmp(cur_argv, "-m32") ||
- if (!*ptr3) {
+ !strcmp(cur_argv, "armv7a-linux-androideabi")) {
- if ((ptr3 = getenv("AFL_LLVM_CTX_K")) == NULL)
- FATAL(
- "you must set the K-CTX K with (e.g. for value 2) "
- "AFL_LLVM_INSTRUMENT=ctx-2");
+ SCAN_KEEP(aflcc->bit_mode, 32);
- }
+ } else if (!strcmp(cur_argv, "-m64")) {
- ctx_k = atoi(ptr3);
- if (ctx_k < 1 || ctx_k > CTX_MAX_K)
- FATAL(
- "K-CTX instrumentation option must be between 1 and CTX_MAX_K "
- "(%u)",
- CTX_MAX_K);
+ SCAN_KEEP(aflcc->bit_mode, 64);
- if (ctx_k == 1) {
+ } else if (strstr(cur_argv, "FORTIFY_SOURCE")) {
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- setenv("AFL_LLVM_CALLER", "1", 1);
- unsetenv("AFL_LLVM_CTX_K");
+ SCAN_KEEP(aflcc->fortify_set, 1);
- } else {
+ } else if (!strcmp(cur_argv, "-x")) {
- instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
- u8 *ptr4 = alloc_printf("%u", ctx_k);
- setenv("AFL_LLVM_CTX_K", ptr4, 1);
+ SCAN_KEEP(aflcc->x_set, 1);
- }
+ } else if (!strcmp(cur_argv, "-E")) {
- }
+ SCAN_KEEP(aflcc->preprocessor_only, 1);
- if (strcasecmp(ptr2, "ctx") == 0) {
+ } else if (!strcmp(cur_argv, "--target=wasm32-wasi")) {
- instrument_opt_mode |= INSTRUMENT_OPT_CTX;
- setenv("AFL_LLVM_CTX", "1", 1);
+ SCAN_KEEP(aflcc->passthrough, 1);
- }
+ } else if (!strcmp(cur_argv, "-c")) {
- if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
+ SCAN_KEEP(aflcc->have_c, 1);
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- setenv("AFL_LLVM_CALLER", "1", 1);
+ } else if (!strcmp(cur_argv, "-static-libasan")) {
- }
+ SCAN_KEEP(aflcc->have_staticasan, 1);
- if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
+ } else if (strstr(cur_argv, "librustc") && strstr(cur_argv, "_rt.asan.a")) {
- u8 *ptr3 = ptr2 + strlen("ngram");
- while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
- ptr3++;
+ SCAN_KEEP(aflcc->have_rust_asanrt, 1);
- if (!*ptr3) {
+ } else if (!strcmp(cur_argv, "-fno-omit-frame-pointer")) {
- if ((ptr3 = getenv("AFL_LLVM_NGRAM_SIZE")) == NULL)
- FATAL(
- "you must set the NGRAM size with (e.g. for value 2) "
- "AFL_LLVM_INSTRUMENT=ngram-2");
+ SCAN_KEEP(aflcc->have_fp, 1);
- }
+ } else if (!strcmp(cur_argv, "-fvisibility=hidden")) {
- ngram_size = atoi(ptr3);
- if (ngram_size < 2 || ngram_size > NGRAM_SIZE_MAX)
- FATAL(
- "NGRAM instrumentation option must be between 2 and "
- "NGRAM_SIZE_MAX (%u)",
- NGRAM_SIZE_MAX);
- instrument_opt_mode |= (INSTRUMENT_OPT_NGRAM);
- u8 *ptr4 = alloc_printf("%u", ngram_size);
- setenv("AFL_LLVM_NGRAM_SIZE", ptr4, 1);
+ SCAN_KEEP(aflcc->have_hidden, 1);
- }
+ } else if (!strcmp(cur_argv, "-flto") || !strcmp(cur_argv, "-flto=full")) {
- ptr2 = strtok(NULL, ":,;");
+ SCAN_KEEP(aflcc->have_flto, 1);
- }
+ } else if (!strncmp(cur_argv, "-D_FORTIFY_SOURCE",
- }
+ strlen("-D_FORTIFY_SOURCE"))) {
- if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
+ SCAN_KEEP(aflcc->have_fortify, 1);
- FATAL("you cannot set CTX and CALLER together");
+ } else if (!strncmp(cur_argv, "-fcf-protection", strlen("-fcf-protection"))) {
- }
+ SCAN_KEEP(aflcc->have_cfisan, 1);
- if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+ } else if (!strncmp(cur_argv, "-O", 2)) {
- FATAL("you cannot set CTX and K-CTX together");
+ SCAN_KEEP(aflcc->have_o, 1);
- }
+ } else if (!strncmp(cur_argv, "-funroll-loop", 13)) {
- if ((instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+ SCAN_KEEP(aflcc->have_unroll, 1);
- FATAL("you cannot set CALLER and K-CTX together");
+ } else if (!strncmp(cur_argv, "--afl", 5)) {
- }
-
- if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT &&
- (compiler_mode == LLVM || compiler_mode == UNSET)) {
+ if (scan)
+ final_ = PARAM_SCAN;
+ else
+ final_ = PARAM_DROP;
- instrument_mode = INSTRUMENT_CLASSIC;
- compiler_mode = LLVM;
+ } else if (!strncmp(cur_argv, "-fno-unroll", 11)) {
- }
+ if (scan)
+ final_ = PARAM_SCAN;
+ else
+ final_ = PARAM_DROP;
- if (!compiler_mode) {
+ } else if (!strcmp(cur_argv, "-pipe") && aflcc->compiler_mode == GCC_PLUGIN) {
- // lto is not a default because outside of afl-cc RANLIB and AR have to
- // be set to llvm versions so this would work
- if (have_llvm)
- compiler_mode = LLVM;
- else if (have_gcc_plugin)
- compiler_mode = GCC_PLUGIN;
- else if (have_gcc)
-#ifdef __APPLE__
- // on OSX clang masquerades as GCC
- compiler_mode = CLANG;
-#else
- compiler_mode = GCC;
-#endif
- else if (have_lto)
- compiler_mode = LTO;
+ if (scan)
+ final_ = PARAM_SCAN;
else
- FATAL("no compiler mode available");
+ final_ = PARAM_DROP;
- }
+ } else if (!strncmp(cur_argv, "-stdlib=", 8) &&
- if (compiler_mode == GCC) {
+ (aflcc->compiler_mode == GCC ||
+ aflcc->compiler_mode == GCC_PLUGIN)) {
- if (clang_mode) {
+ if (scan) {
- instrument_mode = INSTRUMENT_CLANG;
+ final_ = PARAM_SCAN;
} else {
- instrument_mode = INSTRUMENT_GCC;
+ if (!be_quiet) WARNF("Found '%s' - stripping!", cur_argv);
+ final_ = PARAM_DROP;
}
- }
+ } else if (cur_argv[0] != '-') {
- if (compiler_mode == CLANG) {
+ /* It's a weak, loose pattern, with very different purpose
+ than others. We handle it at last, cautiously and robustly. */
- instrument_mode = INSTRUMENT_CLANG;
- setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
+ if (scan && cur_argv[0] != '@') // response file support
+ aflcc->non_dash = 1;
}
+#undef SCAN_KEEP
+
+ if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
+
+ return final_;
+
+}
+
+/** Miscellaneous routines -----END----- **/
+
+/* Print help message on request */
+static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
+
if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) {
printf("afl-cc" VERSION
@@ -2091,36 +2793,44 @@ int main(int argc, char **argv, char **envp) {
"-------------|\n"
"MODES: NCC PERSIST DICT LAF "
"CMPLOG SELECT\n"
- " [LTO] llvm LTO: %s%s\n"
- " PCGUARD DEFAULT yes yes yes yes yes "
- " yes\n"
- " CLASSIC yes yes yes yes yes "
- " yes\n"
- " [LLVM] llvm: %s%s\n"
- " PCGUARD %s yes yes module yes yes "
+ " [LLVM] LLVM: %s%s\n"
+ " PCGUARD %s yes yes module yes yes "
"yes\n"
- " CLASSIC %s no yes module yes yes "
+ " NATIVE AVAILABLE no yes no no "
+ "part. yes\n"
+ " CLASSIC %s no yes module yes yes "
"yes\n"
" - NORMAL\n"
" - CALLER\n"
" - CTX\n"
" - NGRAM-{2-16}\n"
+ " [LTO] LLVM LTO: %s%s\n"
+ " PCGUARD DEFAULT yes yes yes yes yes "
+ " yes\n"
+ " CLASSIC yes yes yes yes yes "
+ " yes\n"
" [GCC_PLUGIN] gcc plugin: %s%s\n"
" CLASSIC DEFAULT no yes no no no "
"yes\n"
" [GCC/CLANG] simple gcc/clang: %s%s\n"
" CLASSIC DEFAULT no no no no no "
"no\n\n",
- have_lto ? "AVAILABLE" : "unavailable!",
- compiler_mode == LTO ? " [SELECTED]" : "",
- have_llvm ? "AVAILABLE" : "unavailable!",
- compiler_mode == LLVM ? " [SELECTED]" : "",
- LLVM_MAJOR >= 7 ? "DEFAULT" : " ",
- LLVM_MAJOR >= 7 ? " " : "DEFAULT",
- have_gcc_plugin ? "AVAILABLE" : "unavailable!",
- compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "",
- have_gcc ? "AVAILABLE" : "unavailable!",
- (compiler_mode == GCC || compiler_mode == CLANG) ? " [SELECTED]" : "");
+ aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
+ aflcc->compiler_mode == LLVM ? " [SELECTED]" : "",
+ aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
+ aflcc->have_llvm ? "AVAILABLE " : "unavailable!",
+ aflcc->have_lto ? "AVAILABLE" : "unavailable!",
+ aflcc->compiler_mode == LTO ? " [SELECTED]" : "",
+ aflcc->have_gcc_plugin ? "AVAILABLE" : "unavailable!",
+ aflcc->compiler_mode == GCC_PLUGIN ? " [SELECTED]" : "",
+ aflcc->have_gcc && aflcc->have_clang
+ ? "AVAILABLE"
+ : (aflcc->have_gcc
+ ? "GCC ONLY "
+ : (aflcc->have_clang ? "CLANG ONLY" : "unavailable!")),
+ (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG)
+ ? " [SELECTED]"
+ : "");
SAYF(
"Modes:\n"
@@ -2166,7 +2876,7 @@ int main(int argc, char **argv, char **envp) {
" (instrumentation/README.lto.md)\n"
" PERSIST: persistent mode support [code] (huge speed increase!)\n"
" (instrumentation/README.persistent_mode.md)\n"
- " DICT: dictionary in the target [yes=automatic or llvm module "
+ " DICT: dictionary in the target [yes=automatic or LLVM module "
"pass]\n"
" (instrumentation/README.lto.md + "
"instrumentation/README.llvm.md)\n"
@@ -2194,7 +2904,7 @@ int main(int argc, char **argv, char **envp) {
" AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n"
" AFL_NO_BUILTIN: no builtins for string compare functions (for "
"libtokencap.so)\n"
- " AFL_NOOP: behave like a normal compiler (to pass configure "
+ " AFL_NOOPT: behave like a normal compiler (to pass configure "
"tests)\n"
" AFL_PATH: path to instrumenting pass and runtime "
"(afl-compiler-rt.*o)\n"
@@ -2209,7 +2919,7 @@ int main(int argc, char **argv, char **envp) {
" AFL_USE_TSAN: activate thread sanitizer\n"
" AFL_USE_LSAN: activate leak-checker sanitizer\n");
- if (have_gcc_plugin)
+ if (aflcc->have_gcc_plugin)
SAYF(
"\nGCC Plugin-specific environment variables:\n"
" AFL_GCC_CMPLOG: log operands of comparisons (RedQueen mutator)\n"
@@ -2225,7 +2935,7 @@ int main(int argc, char **argv, char **envp) {
#define COUNTER_BEHAVIOUR \
" AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n"
#endif
- if (have_llvm)
+ if (aflcc->have_llvm)
SAYF(
"\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment "
"variables:\n"
@@ -2238,6 +2948,10 @@ int main(int argc, char **argv, char **envp) {
"comparisons\n"
" AFL_LLVM_DICT2FILE_NO_MAIN: skip parsing main() for the "
"dictionary\n"
+ " AFL_LLVM_INJECTIONS_ALL: enables all injections hooking\n"
+ " AFL_LLVM_INJECTIONS_SQL: enables SQL injections hooking\n"
+ " AFL_LLVM_INJECTIONS_LDAP: enables LDAP injections hooking\n"
+ " AFL_LLVM_INJECTIONS_XSS: enables XSS injections hooking\n"
" AFL_LLVM_LAF_ALL: enables all LAF splits/transforms\n"
" AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n"
" AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n"
@@ -2249,7 +2963,7 @@ int main(int argc, char **argv, char **envp) {
"instrument allow/\n"
" deny listing (selective instrumentation)\n");
- if (have_llvm)
+ if (aflcc->have_llvm)
SAYF(
" AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen "
"mutator)\n"
@@ -2263,10 +2977,12 @@ int main(int argc, char **argv, char **envp) {
" AFL_LLVM_CTX: use full context sensitive coverage (for "
"CLASSIC)\n"
" AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage (for "
- "CLASSIC)\n");
+ "CLASSIC)\n"
+ " AFL_LLVM_NO_RPATH: disable rpath setting for custom LLVM "
+ "locations\n");
#ifdef AFL_CLANG_FLTO
- if (have_lto)
+ if (aflcc->have_lto)
SAYF(
"\nLTO/afl-clang-lto specific environment variables:\n"
" AFL_LLVM_MAP_ADDR: use a fixed coverage map address (speed), "
@@ -2274,12 +2990,13 @@ int main(int argc, char **argv, char **envp) {
"0x10000\n"
" AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
"functions\n"
- " into this file\n"
+ " into this file (LTO mode)\n"
+ " AFL_LLVM_LTO_CALLER: activate CALLER/CTX instrumentation\n"
+ " AFL_LLVM_LTO_CALLER_DEPTH: skip how many empty functions\n"
" AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
"global var\n"
" AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
- "a "
- "bb\n"
+ "a bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n"
" AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
@@ -2302,9 +3019,9 @@ int main(int argc, char **argv, char **envp) {
"targets.\n\n");
#if (LLVM_MAJOR >= 3)
- if (have_lto)
+ if (aflcc->have_lto)
SAYF("afl-cc LTO with ld=%s %s\n", AFL_REAL_LD, AFL_CLANG_FLTO);
- if (have_llvm)
+ if (aflcc->have_llvm)
SAYF("afl-cc LLVM version %d using the binary path \"%s\".\n", LLVM_MAJOR,
LLVM_BINDIR);
#endif
@@ -2330,209 +3047,498 @@ int main(int argc, char **argv, char **envp) {
"AFL_LLVM_CMPLOG and "
"AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
+ if (LLVM_MAJOR < 13) {
+
+ SAYF(
+ "Warning: It is highly recommended to use at least LLVM version 13 "
+ "(or better, higher) rather than %d!\n\n",
+ LLVM_MAJOR);
+
+ }
+
exit(1);
}
- if (compiler_mode == LTO) {
+}
- if (instrument_mode == 0 || instrument_mode == INSTRUMENT_LTO ||
- instrument_mode == INSTRUMENT_CFG ||
- instrument_mode == INSTRUMENT_PCGUARD) {
+/*
+ Process params passed to afl-cc.
+
+ We have two working modes, *scan* and *non-scan*. In scan mode,
+ the main task is to set some variables in aflcc according to current argv[i],
+ while in non-scan mode, is to choose keep or drop current argv[i].
+
+ We have several matching routines being called sequentially in the while-loop,
+ and each of them try to parse and match current argv[i] according to their own
+ rules. If one miss match, the next will then take over. In non-scan mode, each
+ argv[i] mis-matched by all the routines will be kept.
+
+ These routines are:
+ 1. parse_misc_params
+ 2. parse_fsanitize
+ 3. parse_linking_params
+ 4. `if (*cur == '@') {...}`, i.e., parse response files
+*/
+static void process_params(aflcc_state_t *aflcc, u8 scan, u32 argc,
+ char **argv) {
- lto_mode = 1;
- // force CFG
- // if (!instrument_mode) {
+ // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
- instrument_mode = INSTRUMENT_PCGUARD;
- // ptr = instrument_mode_string[instrument_mode];
- // }
+ /* Process the argument list. */
- } else if (instrument_mode == INSTRUMENT_CLASSIC) {
+ u8 skip_next = 0;
+ while (--argc) {
- lto_mode = 1;
+ u8 *cur = *(++argv);
- } else {
+ if (skip_next > 0) {
- if (!be_quiet) {
+ skip_next--;
+ continue;
- WARNF("afl-clang-lto called with mode %s, using that mode instead",
- instrument_mode_string[instrument_mode]);
+ }
+
+ if (PARAM_MISS != parse_misc_params(aflcc, cur, scan)) continue;
+
+ if (PARAM_MISS != parse_fsanitize(aflcc, cur, scan)) continue;
+
+ if (PARAM_MISS != parse_linking_params(aflcc, cur, scan, &skip_next, argv))
+ continue;
+
+ /* Response file support -----BEGIN-----
+ We have two choices - move everything to the command line or
+ rewrite the response files to temporary files and delete them
+ afterwards. We choose the first for easiness.
+ For clang, llvm::cl::ExpandResponseFiles does this, however it
+ only has C++ interface. And for gcc there is expandargv in libiberty,
+ written in C, but we can't simply copy-paste since its LGPL licensed.
+ So here we use an equivalent FSM as alternative, and try to be compatible
+ with the two above. See:
+ - https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
+ - driver::expand_at_files in gcc.git/gcc/gcc.c
+ - expandargv in gcc.git/libiberty/argv.c
+ - llvm-project.git/clang/tools/driver/driver.cpp
+ - ExpandResponseFiles in
+ llvm-project.git/llvm/lib/Support/CommandLine.cpp
+ */
+ if (*cur == '@') {
+
+ u8 *filename = cur + 1;
+ if (aflcc->debug) { DEBUGF("response file=%s\n", filename); }
+
+ // Check not found or empty? let the compiler complain if so.
+ FILE *f = fopen(filename, "r");
+ if (!f) {
+
+ if (!scan) insert_param(aflcc, cur);
+ continue;
}
- }
+ struct stat st;
+ if (fstat(fileno(f), &st) || !S_ISREG(st.st_mode) || st.st_size < 1) {
- }
+ fclose(f);
+ if (!scan) insert_param(aflcc, cur);
+ continue;
- if (instrument_mode == 0 && compiler_mode < GCC_PLUGIN) {
+ }
-#if LLVM_MAJOR >= 7
- #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
- if (have_instr_env) {
+ // Limit the number of response files, the max value
+ // just keep consistent with expandargv. Only do this in
+ // scan mode, and not touch rsp_count anymore in the next.
+ static u32 rsp_count = 2000;
+ if (scan) {
- instrument_mode = INSTRUMENT_AFL;
- if (!be_quiet) {
+ if (rsp_count == 0) FATAL("Too many response files provided!");
- WARNF(
- "Switching to classic instrumentation because "
- "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
+ --rsp_count;
}
- } else
+ // argc, argv acquired from this rsp file. Note that
+ // process_params ignores argv[0], we need to put a const "" here.
+ u32 argc_read = 1;
+ char **argv_read = ck_alloc(sizeof(char *));
+ argv_read[0] = "";
- #endif
- instrument_mode = INSTRUMENT_PCGUARD;
+ char *arg_buf = NULL;
+ u64 arg_len = 0;
-#else
- instrument_mode = INSTRUMENT_AFL;
-#endif
+ enum fsm_state {
- }
+ fsm_whitespace, // whitespace seen so far
+ fsm_double_quote, // have unpaired double quote
+ fsm_single_quote, // have unpaired single quote
+ fsm_backslash, // a backslash is seen with no unpaired quote
+ fsm_normal // a normal char is seen
- if (instrument_opt_mode && compiler_mode != LLVM)
- FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
+ };
- if (!instrument_opt_mode) {
+ // Workaround to append c to arg buffer, and append the buffer to argv
+#define ARG_ALLOC(c) \
+ do { \
+ \
+ ++arg_len; \
+ arg_buf = ck_realloc(arg_buf, (arg_len + 1) * sizeof(char)); \
+ arg_buf[arg_len] = '\0'; \
+ arg_buf[arg_len - 1] = (char)c; \
+ \
+ } while (0)
- if (lto_mode && instrument_mode == INSTRUMENT_CFG)
- instrument_mode = INSTRUMENT_PCGUARD;
- ptr = instrument_mode_string[instrument_mode];
+#define ARG_STORE() \
+ do { \
+ \
+ ++argc_read; \
+ argv_read = ck_realloc(argv_read, argc_read * sizeof(char *)); \
+ argv_read[argc_read - 1] = arg_buf; \
+ arg_buf = NULL; \
+ arg_len = 0; \
+ \
+ } while (0)
- } else {
+ int cur_chr = (int)' '; // init as whitespace, as a good start :)
+ enum fsm_state state_ = fsm_whitespace;
- char *ptr2 = alloc_printf(" + NGRAM-%u", ngram_size);
- char *ptr3 = alloc_printf(" + K-CTX-%u", ctx_k);
+ while (cur_chr != EOF) {
- ptr = alloc_printf(
- "%s%s%s%s%s", instrument_mode_string[instrument_mode],
- (instrument_opt_mode & INSTRUMENT_OPT_CTX) ? " + CTX" : "",
- (instrument_opt_mode & INSTRUMENT_OPT_CALLER) ? " + CALLER" : "",
- (instrument_opt_mode & INSTRUMENT_OPT_NGRAM) ? ptr2 : "",
- (instrument_opt_mode & INSTRUMENT_OPT_CTX_K) ? ptr3 : "");
+ switch (state_) {
- ck_free(ptr2);
- ck_free(ptr3);
+ case fsm_whitespace:
- }
+ if (arg_buf) {
-#ifndef AFL_CLANG_FLTO
- if (lto_mode)
- FATAL(
- "instrumentation mode LTO specified but LLVM support not available "
- "(requires LLVM 11 or higher)");
-#endif
+ ARG_STORE();
+ break;
- if (instrument_opt_mode && instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
- instrument_mode != INSTRUMENT_CLASSIC)
- FATAL(
- "CALLER, CTX and NGRAM instrumentation options can only be used with "
- "the LLVM CLASSIC instrumentation mode.");
+ }
- if (getenv("AFL_LLVM_SKIP_NEVERZERO") && getenv("AFL_LLVM_NOT_ZERO"))
- FATAL(
- "AFL_LLVM_NOT_ZERO and AFL_LLVM_SKIP_NEVERZERO can not be set "
- "together");
+ if (isspace(cur_chr)) {
-#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
- if (instrument_mode == INSTRUMENT_PCGUARD && have_instr_env) {
+ cur_chr = fgetc(f);
- FATAL(
- "Instrumentation type PCGUARD does not support "
- "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
+ } else if (cur_chr == (int)'\'') {
- }
+ state_ = fsm_single_quote;
+ cur_chr = fgetc(f);
-#endif
+ } else if (cur_chr == (int)'"') {
- u8 *ptr2;
+ state_ = fsm_double_quote;
+ cur_chr = fgetc(f);
- if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
- FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
+ } else if (cur_chr == (int)'\\') {
- if ((isatty(2) && !be_quiet) || debug) {
+ state_ = fsm_backslash;
+ cur_chr = fgetc(f);
- SAYF(cCYA
- "afl-cc" VERSION cRST
- " by Michal Zalewski, Laszlo Szekeres, Marc Heuse - mode: %s-%s\n",
- compiler_mode_string[compiler_mode], ptr);
+ } else {
- }
+ state_ = fsm_normal;
- if (!be_quiet && (compiler_mode == GCC || compiler_mode == CLANG)) {
+ }
- WARNF(
- "You are using outdated instrumentation, install LLVM and/or "
- "gcc-plugin and use afl-clang-fast/afl-clang-lto/afl-gcc-fast "
- "instead!");
+ break;
+
+ case fsm_normal:
+
+ if (isspace(cur_chr)) {
+
+ state_ = fsm_whitespace;
+
+ } else if (cur_chr == (int)'\'') {
+
+ state_ = fsm_single_quote;
+ cur_chr = fgetc(f);
+
+ } else if (cur_chr == (int)'\"') {
+
+ state_ = fsm_double_quote;
+ cur_chr = fgetc(f);
+
+ } else if (cur_chr == (int)'\\') {
+
+ state_ = fsm_backslash;
+ cur_chr = fgetc(f);
+
+ } else {
+
+ ARG_ALLOC(cur_chr);
+ cur_chr = fgetc(f);
+
+ }
+
+ break;
+
+ case fsm_backslash:
+
+ ARG_ALLOC(cur_chr);
+ cur_chr = fgetc(f);
+ state_ = fsm_normal;
+
+ break;
+
+ case fsm_single_quote:
+
+ if (cur_chr == (int)'\\') {
+
+ cur_chr = fgetc(f);
+ if (cur_chr == EOF) break;
+ ARG_ALLOC(cur_chr);
+
+ } else if (cur_chr == (int)'\'') {
+
+ state_ = fsm_normal;
+
+ } else {
+
+ ARG_ALLOC(cur_chr);
+
+ }
+
+ cur_chr = fgetc(f);
+ break;
+
+ case fsm_double_quote:
+
+ if (cur_chr == (int)'\\') {
+
+ cur_chr = fgetc(f);
+ if (cur_chr == EOF) break;
+ ARG_ALLOC(cur_chr);
+
+ } else if (cur_chr == (int)'"') {
+
+ state_ = fsm_normal;
+
+ } else {
+
+ ARG_ALLOC(cur_chr);
+
+ }
+
+ cur_chr = fgetc(f);
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ if (arg_buf) { ARG_STORE(); } // save the pending arg after EOF
+
+#undef ARG_ALLOC
+#undef ARG_STORE
+
+ if (argc_read > 1) { process_params(aflcc, scan, argc_read, argv_read); }
+
+ // We cannot free argv_read[] unless we don't need to keep any
+ // reference in cc_params. Never free argv[0], the const "".
+ if (scan) {
+
+ while (argc_read > 1)
+ ck_free(argv_read[--argc_read]);
+
+ ck_free(argv_read);
+
+ }
+
+ continue;
+
+ } /* Response file support -----END----- */
+
+ if (!scan) insert_param(aflcc, cur);
}
- if (debug) {
+}
- DEBUGF("cd '%s';", getthecwd());
- for (i = 0; i < argc; i++)
- SAYF(" '%s'", argv[i]);
- SAYF("\n");
- fflush(stdout);
- fflush(stderr);
+/* Process each of the existing argv, also add a few new args. */
+static void edit_params(aflcc_state_t *aflcc, u32 argc, char **argv,
+ char **envp) {
+
+ add_real_argv0(aflcc);
+
+ // prevent unnecessary build errors
+ if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC) {
+
+ insert_param(aflcc, "-Wno-unused-command-line-argument");
}
- if (getenv("AFL_LLVM_LAF_ALL")) {
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) {
- setenv("AFL_LLVM_LAF_SPLIT_SWITCHES", "1", 1);
- setenv("AFL_LLVM_LAF_SPLIT_COMPARES", "1", 1);
- setenv("AFL_LLVM_LAF_SPLIT_FLOATS", "1", 1);
- setenv("AFL_LLVM_LAF_TRANSFORM_COMPARES", "1", 1);
+ add_assembler(aflcc);
}
- cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
- getenv("AFL_GCC_CMPLOG");
+ if (aflcc->compiler_mode == GCC_PLUGIN) { add_gcc_plugin(aflcc); }
-#if !defined(__ANDROID__) && !defined(ANDROID)
- ptr = find_object("afl-compiler-rt.o", argv[0]);
+ if (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == LTO) {
- if (!ptr) {
+ if (aflcc->lto_mode && aflcc->have_instr_env) {
- FATAL(
- "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
- "environment variable.");
+ load_llvm_pass(aflcc, "afl-llvm-lto-instrumentlist.so");
- }
+ }
- if (debug) { DEBUGF("rt=%s obj_path=%s\n", ptr, obj_path); }
+ if (getenv("AFL_LLVM_DICT2FILE")) {
- ck_free(ptr);
-#endif
+ load_llvm_pass(aflcc, "afl-llvm-dict2file.so");
- edit_params(argc, argv, envp);
+ }
- if (debug) {
+ // laf
+ if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
- DEBUGF("cd '%s';", getthecwd());
- for (i = 0; i < (s32)cc_par_cnt; i++)
- SAYF(" '%s'", cc_params[i]);
- SAYF("\n");
- fflush(stdout);
- fflush(stderr);
+ load_llvm_pass(aflcc, "split-switches-pass.so");
+
+ }
+
+ if (getenv("LAF_TRANSFORM_COMPARES") ||
+ getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
+
+ load_llvm_pass(aflcc, "compare-transform-pass.so");
+
+ }
+
+ if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
+ getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
+
+ load_llvm_pass(aflcc, "split-compares-pass.so");
+
+ }
+
+ // /laf
+
+ if (aflcc->cmplog_mode) {
+
+ insert_param(aflcc, "-fno-inline");
+
+ load_llvm_pass(aflcc, "cmplog-switches-pass.so");
+ // reuse split switches from laf
+ load_llvm_pass(aflcc, "split-switches-pass.so");
+
+ }
+
+ // #if LLVM_MAJOR >= 13
+ // // Use the old pass manager in LLVM 14 which the AFL++ passes still
+ // use. insert_param(aflcc, "-flegacy-pass-manager");
+ // #endif
+
+ if (aflcc->lto_mode) {
+
+ insert_param(aflcc, aflcc->lto_flag);
+
+ if (!aflcc->have_c) {
+
+ add_lto_linker(aflcc);
+ add_lto_passes(aflcc);
+
+ }
+
+ } else {
+
+ if (aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
+
+ add_optimized_pcguard(aflcc);
+
+ } else if (aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
+
+ add_native_pcguard(aflcc);
+
+ } else {
+
+ load_llvm_pass(aflcc, "afl-llvm-pass.so");
+
+ }
+
+ }
+
+ if (aflcc->cmplog_mode) {
+
+ load_llvm_pass(aflcc, "cmplog-instructions-pass.so");
+ load_llvm_pass(aflcc, "cmplog-routines-pass.so");
+
+ }
+
+ if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
+ getenv("AFL_LLVM_INJECTIONS_SQL") ||
+ getenv("AFL_LLVM_INJECTIONS_LDAP") ||
+ getenv("AFL_LLVM_INJECTIONS_XSS")) {
+
+ load_llvm_pass(aflcc, "injection-pass.so");
+
+ }
+
+ // insert_param(aflcc, "-Qunused-arguments");
}
- if (passthrough) {
+ /* Inspect the command line parameters. */
+
+ process_params(aflcc, 0, argc, argv);
+
+ add_sanitizers(aflcc, envp);
+
+ add_misc_params(aflcc);
+
+ add_defs_common(aflcc);
+ add_defs_selective_instr(aflcc);
+ add_defs_persistent_mode(aflcc);
+
+ add_runtime(aflcc);
+
+ insert_param(aflcc, NULL);
+
+}
+
+/* Main entry point */
+int main(int argc, char **argv, char **envp) {
+
+ aflcc_state_t *aflcc = malloc(sizeof(aflcc_state_t));
+ aflcc_state_init(aflcc, (u8 *)argv[0]);
+
+ check_environment_vars(envp);
+
+ find_built_deps(aflcc);
+
+ compiler_mode_by_callname(aflcc);
+ compiler_mode_by_environ(aflcc);
+ compiler_mode_by_cmdline(aflcc, argc, argv);
+
+ instrument_mode_by_environ(aflcc);
+
+ mode_final_checkout(aflcc, argc, argv);
+
+ process_params(aflcc, 1, argc, argv);
+
+ maybe_usage(aflcc, argc, argv);
+
+ mode_notification(aflcc);
+
+ if (aflcc->debug) debugf_args(argc, argv);
+
+ edit_params(aflcc, argc, argv, envp);
+
+ if (aflcc->debug)
+ debugf_args((s32)aflcc->cc_par_cnt, (char **)aflcc->cc_params);
+
+ if (aflcc->passthrough) {
- argv[0] = cc_params[0];
- execvp(cc_params[0], (char **)argv);
+ argv[0] = aflcc->cc_params[0];
+ execvp(aflcc->cc_params[0], (char **)argv);
} else {
- execvp(cc_params[0], (char **)cc_params);
+ execvp(aflcc->cc_params[0], (char **)aflcc->cc_params);
}
- FATAL("Oops, failed to execute '%s' - check your PATH", cc_params[0]);
+ FATAL("Oops, failed to execute '%s' - check your PATH", aflcc->cc_params[0]);
return 0;
diff --git a/src/afl-common.c b/src/afl-common.c
index a5c48e80..9a27824d 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -34,6 +34,7 @@
#endif
#include <string.h>
#include <strings.h>
+#include <time.h>
#include <math.h>
#include <sys/mman.h>
@@ -58,6 +59,27 @@ u8 last_intr = 0;
#define AFL_PATH "/usr/local/lib/afl/"
#endif
+/* - Some BSD (i.e.: FreeBSD) offer the FAST clock source as
+ * equivalent to Linux COARSE clock source. Aliasing COARSE to
+ * FAST on such systems when COARSE is not already defined.
+ * - macOS has no support of CLOCK_MONOTONIC_COARSE clock type.
+ */
+#if defined(OS_DARWIN) || defined(OS_SUNOS) || defined(__APPLE__) || \
+ defined(__sun) || defined(__NetBSD__)
+ #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
+#elif defined(OS_FREEBSD)
+ #define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC_FAST
+#endif
+
+/* Convert seconds to milliseconds. */
+#define SEC_TO_MS(sec) ((sec) * 1000)
+/* Convert seconds to microseconds. */
+#define SEC_TO_US(sec) ((sec) * 1000000)
+/* Convert nanoseconds to milliseconds. */
+#define NS_TO_MS(ns) ((ns) / 1000000)
+/* Convert nanoseconds to microseconds. */
+#define NS_TO_US(ns) ((ns) / 1000)
+
void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
size_t needlelen) {
@@ -86,9 +108,10 @@ void set_sanitizer_defaults() {
u8 *have_lsan_options = getenv("LSAN_OPTIONS");
u8 have_san_options = 0;
u8 default_options[1024] =
- "detect_odr_violation=0:abort_on_error=1:symbolize=0:allocator_may_"
- "return_null=1:handle_segv=0:handle_sigbus=0:handle_abort=0:handle_"
- "sigfpe=0:handle_sigill=0:";
+ "detect_odr_violation=0:abort_on_error=1:symbolize=0:"
+ "allocator_may_return_null=1:handle_segv=0:handle_sigbus=0:"
+ "handle_abort=0:handle_sigfpe=0:handle_sigill=0:"
+ "detect_stack_use_after_return=0:check_initialization_order=0:";
if (have_asan_options || have_ubsan_options || have_msan_options ||
have_lsan_options) {
@@ -98,12 +121,27 @@ void set_sanitizer_defaults() {
}
/* LSAN does not support abort_on_error=1. (is this still true??) */
+ u8 should_detect_leaks = 0;
if (!have_lsan_options) {
u8 buf[2048] = "";
if (!have_san_options) { strcpy(buf, default_options); }
- strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=1:malloc_context_size=30:");
+ if (have_asan_options) {
+
+ if (NULL != strstr(have_asan_options, "detect_leaks=0")) {
+
+ strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=0:malloc_context_size=0:");
+
+ } else {
+
+ should_detect_leaks = 1;
+ strcat(buf, "exitcode=" STRINGIFY(LSAN_ERROR) ":fast_unwind_on_malloc=0:print_suppressions=0:detect_leaks=1:malloc_context_size=30:");
+
+ }
+
+ }
+
setenv("LSAN_OPTIONS", buf, 1);
}
@@ -112,7 +150,15 @@ void set_sanitizer_defaults() {
if (!have_lsan_options) {
- strcat(default_options, "detect_leaks=0:malloc_context_size=0:");
+ if (should_detect_leaks) {
+
+ strcat(default_options, "detect_leaks=1:malloc_context_size=30:");
+
+ } else {
+
+ strcat(default_options, "detect_leaks=0:malloc_context_size=0:");
+
+ }
}
@@ -403,7 +449,7 @@ u8 *find_binary(u8 *fname) {
FATAL(
"Unexpected overflow when processing ENV. This should never "
- "happend.");
+ "had happened.");
}
@@ -949,14 +995,18 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) {
/* Get unix time in milliseconds */
-u64 get_cur_time(void) {
+inline u64 get_cur_time(void) {
+
+ struct timespec ts;
+ int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+ if (rc == -1) {
- struct timeval tv;
- struct timezone tz;
+ PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno,
+ strerror(errno));
- gettimeofday(&tv, &tz);
+ }
- return (tv.tv_sec * 1000ULL) + (tv.tv_usec / 1000);
+ return SEC_TO_MS((uint64_t)ts.tv_sec) + NS_TO_MS((uint64_t)ts.tv_nsec);
}
@@ -964,12 +1014,16 @@ u64 get_cur_time(void) {
u64 get_cur_time_us(void) {
- struct timeval tv;
- struct timezone tz;
+ struct timespec ts;
+ int rc = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+ if (rc == -1) {
- gettimeofday(&tv, &tz);
+ PFATAL("Failed to obtain timestamp (errno = %i: %s)\n", errno,
+ strerror(errno));
- return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
+ }
+
+ return SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec);
}
@@ -1298,6 +1352,35 @@ u8 *u_stringify_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
}
+/* Unsafe describe time delta as simple string.
+ Returns a pointer to buf for convenience. */
+
+u8 *u_simplestring_time_diff(u8 *buf, u64 cur_ms, u64 event_ms) {
+
+ if (!event_ms) {
+
+ sprintf(buf, "00:00:00");
+
+ } else {
+
+ u64 delta;
+ s32 t_d, t_h, t_m, t_s;
+
+ delta = cur_ms - event_ms;
+
+ t_d = delta / 1000 / 60 / 60 / 24;
+ t_h = (delta / 1000 / 60 / 60) % 24;
+ t_m = (delta / 1000 / 60) % 60;
+ t_s = (delta / 1000) % 60;
+
+ sprintf(buf, "%d:%02d:%02d:%02d", t_d, t_h, t_m, t_s);
+
+ }
+
+ return buf;
+
+}
+
/* Reads the map size from ENV */
u32 get_map_size(void) {
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index 30c8901c..beb6bdeb 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -7,13 +7,13 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com> and
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -27,6 +27,9 @@
*/
#include "config.h"
+#ifdef AFL_PERSISTENT_RECORD
+ #include "afl-fuzz.h"
+#endif
#include "types.h"
#include "debug.h"
#include "common.h"
@@ -129,6 +132,10 @@ nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir");
if (plugin->nyx_remove_work_dir == NULL) { goto fail; }
+ plugin->nyx_config_set_aux_buffer_size =
+ dlsym(handle, "nyx_config_set_aux_buffer_size");
+ if (plugin->nyx_config_set_aux_buffer_size == NULL) { goto fail; }
+
OKF("libnyx plugin is ready!");
return plugin;
@@ -160,6 +167,8 @@ void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
}
+ if (fsrv->nyx_log_fd >= 0) { close(fsrv->nyx_log_fd); }
+
}
}
@@ -214,6 +223,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
fsrv->nyx_use_tmp_workdir = false;
fsrv->nyx_tmp_workdir_path = NULL;
+ fsrv->nyx_log_fd = -1;
#endif
// this structure needs default so we initialize it if this was not done
@@ -265,6 +275,7 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) {
fsrv_to->uses_crash_exitcode = from->uses_crash_exitcode;
fsrv_to->crash_exitcode = from->crash_exitcode;
fsrv_to->child_kill_signal = from->child_kill_signal;
+ fsrv_to->fsrv_kill_signal = from->fsrv_kill_signal;
fsrv_to->debug = from->debug;
// These are forkserver specific.
@@ -381,7 +392,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
while (1) {
uint32_t was_killed;
- int status;
+ u32 status;
/* Wait for parent by reading from the pipe. Exit if read fails. */
@@ -516,7 +527,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2];
- s32 status;
+ u32 status;
s32 rlen;
char *ignore_autodict = getenv("AFL_NO_AUTODICT");
@@ -567,10 +578,26 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
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_size(nyx_config, fsrv->max_length);
fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
true);
+ char *nyx_log_path = getenv("AFL_NYX_LOG");
+ if (nyx_log_path) {
+
+ fsrv->nyx_log_fd =
+ open(nyx_log_path, O_CREAT | O_TRUNC | O_WRONLY, DEFAULT_PERMISSION);
+ if (fsrv->nyx_log_fd < 0) {
+
+ NYX_PRE_FATAL(fsrv, "AFL_NYX_LOG path could not be written");
+
+ }
+
+ fsrv->nyx_handlers->nyx_config_set_hprintf_fd(nyx_config,
+ fsrv->nyx_log_fd);
+
+ }
+
if (fsrv->nyx_standalone) {
fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone);
@@ -589,23 +616,42 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
- if (getenv("NYX_REUSE_SNAPSHOT") != NULL) {
+ if (getenv("AFL_NYX_AUX_SIZE") != NULL) {
+
+ fsrv->nyx_aux_string_len = atoi(getenv("AFL_NYX_AUX_SIZE"));
+
+ if (fsrv->nyx_handlers->nyx_config_set_aux_buffer_size(
+ nyx_config, fsrv->nyx_aux_string_len) != 1) {
+
+ NYX_PRE_FATAL(fsrv,
+ "Invalid AFL_NYX_AUX_SIZE value set (must be a multiple "
+ "of 4096) ...");
+
+ }
+
+ } else {
+
+ fsrv->nyx_aux_string_len = 0x1000;
+
+ }
+
+ if (getenv("AFL_NYX_REUSE_SNAPSHOT") != NULL) {
- if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+ if (access(getenv("AFL_NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
- NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist");
+ NYX_PRE_FATAL(fsrv, "AFL_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"));
+ alloc_printf("%s/global.state", getenv("AFL_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");
+ NYX_PRE_FATAL(fsrv,
+ "AFL_NYX_REUSE_SNAPSHOT path does not contain a valid "
+ "Nyx snapshot");
}
@@ -617,13 +663,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
char *workdir_snapshot_path =
alloc_printf("%s/workdir/snapshot", outdir_path_absolute);
char *reuse_snapshot_path_real =
- realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL);
+ realpath(getenv("AFL_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)");
+ NYX_PRE_FATAL(
+ fsrv,
+ "AFL_NYX_REUSE_SNAPSHOT path is located in current workdir "
+ "(use another output directory)");
}
@@ -631,12 +678,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
ck_free(workdir_snapshot_path);
fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(
- nyx_config, getenv("NYX_REUSE_SNAPSHOT"));
+ nyx_config, getenv("AFL_NYX_REUSE_SNAPSHOT"));
}
- fsrv->nyx_runner =
- fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id);
+ fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_id);
ck_free(workdir_path);
ck_free(outdir_path_absolute);
@@ -653,27 +699,27 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
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_runner, getenv("AFL_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);
- fsrv->nyx_aux_string = malloc(0x1000);
- memset(fsrv->nyx_aux_string, 0, 0x1000);
+ fsrv->nyx_aux_string = malloc(fsrv->nyx_aux_string_len);
+ memset(fsrv->nyx_aux_string, 0, fsrv->nyx_aux_string_len);
/* 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:
- NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx abort occurred...");
break;
case IoError:
NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died...");
break;
case Error:
- NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occurred...");
break;
default:
break;
@@ -681,7 +727,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
}
/* autodict in Nyx mode */
- if (!ignore_autodict) {
+ if (!ignore_autodict && fsrv->add_extra_func) {
char *x =
alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
@@ -974,75 +1020,68 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (rlen == 4) {
- if (!be_quiet) { OKF("All right - fork server is up."); }
+ /*
+ * The new fork server model works like this:
+ * Client: sends "AFLx" in little endian, with x being the forkserver
+ * protocol version.
+ * Server: replies with XOR of the message or exits with an error if it
+ * is not a supported version.
+ * Client: sends 32 bit of options and then sends all parameters of
+ * the options, one after another, increasing by option number.
+ * Ends with "AFLx".
+ * After the initial protocol version confirmation the server does not
+ * send any data anymore - except a future option requires this.
+ */
- if (getenv("AFL_DEBUG")) {
+ if ((status & FS_NEW_ERROR) == FS_NEW_ERROR) {
- ACTF("Extended forkserver functions received (%08x).", status);
+ report_error_and_exit(status & 0x0000ffff);
}
- if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
- report_error_and_exit(FS_OPT_GET_ERROR(status));
+ if (status >= 0x41464c00 && status <= 0x41464cff) {
- if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
+ u32 version = status - 0x41464c00;
- // workaround for recent AFL++ versions
- if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
- status = (status & 0xf0ffffff);
+ if (!version) {
- if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
+ FATAL(
+ "Fork server version is not assigned, this should not happen. "
+ "Recompile target.");
- if (fsrv->qemu_mode || fsrv->frida_mode) {
+ } else if (version < FS_NEW_VERSION_MIN || version > FS_NEW_VERSION_MAX) {
- report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
-
- } else {
-
- report_error_and_exit(FS_ERROR_OLD_CMPLOG);
-
- }
+ FATAL(
+ "Fork server version is not not supported. Recompile the target.");
}
- if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
+ u32 keep = status;
+ status ^= 0xffffffff;
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
- fsrv->snapshot = 1;
- if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
+ FATAL("Writing to forkserver failed.");
}
- if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
-
- if (fsrv->support_shmem_fuzz) {
-
- fsrv->use_shmem_fuzz = 1;
- if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
-
- if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
-
- u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
- if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
+ if (!be_quiet) {
- FATAL("Writing to forkserver failed.");
-
- }
+ OKF("All right - new fork server model v%u is up.", version);
- }
+ }
- } else {
+ rlen = read(fsrv->fsrv_st_fd, &status, 4);
- FATAL(
- "Target requested sharedmem fuzzing, but we failed to enable "
- "it.");
+ if (getenv("AFL_DEBUG")) {
- }
+ ACTF("Forkserver options received: (0x%08x)", status);
}
- if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
+ if ((status & FS_NEW_OPT_MAPSIZE)) {
- u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
+ u32 tmp_map_size;
+ rlen = read(fsrv->fsrv_st_fd, &tmp_map_size, 4);
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
@@ -1059,7 +1098,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
FATAL(
"Target's coverage map size of %u is larger than the one this "
- "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart "
+ "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
+ "restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
@@ -1068,106 +1108,326 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
fsrv->map_size = tmp_map_size;
+ } else {
+
+ fsrv->real_map_size = fsrv->map_size = MAP_SIZE;
+
}
- if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
+ if (status & FS_NEW_OPT_SHDMEM_FUZZ) {
+
+ if (fsrv->support_shmem_fuzz) {
- if (!ignore_autodict) {
+ fsrv->use_shmem_fuzz = 1;
+ if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
- if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
+ } else {
- // this is not afl-fuzz - or it is cmplog - we deny and return
- if (fsrv->use_shmem_fuzz) {
+ FATAL(
+ "Target requested sharedmem fuzzing, but we failed to enable "
+ "it.");
- status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+ }
- } else {
+ }
- status = (FS_OPT_ENABLED);
+ if (status & FS_NEW_OPT_AUTODICT) {
- }
+ // even if we do not need the dictionary we have to read it
- if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+ u32 dict_size;
+ if (read(fsrv->fsrv_st_fd, &dict_size, 4) != 4) {
- FATAL("Writing to forkserver failed.");
+ FATAL("Reading from forkserver failed.");
- }
+ }
- return;
+ if (dict_size < 2 || dict_size > 0xffffff) {
- }
+ FATAL("Dictionary has an illegal size: %d", dict_size);
+
+ }
+
+ u32 offset = 0, count = 0;
+ u8 *dict = ck_alloc(dict_size);
+ if (dict == NULL) {
+
+ FATAL("Could not allocate %u bytes of autodictionary memory",
+ dict_size);
+
+ }
- if (!be_quiet) { ACTF("Using AUTODICT feature."); }
+ while (offset < dict_size) {
- if (fsrv->use_shmem_fuzz) {
+ rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size - offset);
+ if (rlen > 0) {
- status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
+ offset += rlen;
} else {
- status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
+ FATAL(
+ "Reading autodictionary fail at position %u with %u bytes "
+ "left.",
+ offset, dict_size - offset);
+
+ }
+
+ }
+
+ offset = 0;
+ while (offset < dict_size && (u8)dict[offset] + offset < dict_size) {
+
+ if (!ignore_autodict && fsrv->add_extra_func) {
+
+ fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
+ (u8)dict[offset]);
+ count++;
}
- if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+ offset += (1 + dict[offset]);
+
+ }
+
+ if (!be_quiet && count) {
+
+ ACTF("Loaded %u autodictionary entries", count);
+
+ }
+
+ ck_free(dict);
+
+ }
+
+ u32 status2;
+ rlen = read(fsrv->fsrv_st_fd, &status2, 4);
+
+ if (status2 != keep) {
+
+ FATAL("Error in forkserver communication (%08x=>%08x)", keep, status2);
+
+ }
+
+ } else {
+
+ if (!fsrv->qemu_mode && !fsrv->cs_mode
+#ifdef __linux__
+ && !fsrv->nyx_mode
+#endif
+ ) {
+
+ WARNF(
+ "Old fork server model is used by the target, this still works "
+ "though.");
+
+ }
+
+ if (!be_quiet) { OKF("All right - old fork server is up."); }
+
+ if (getenv("AFL_DEBUG")) {
+
+ ACTF("Extended forkserver functions received (%08x).", status);
+
+ }
+
+ if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
+ report_error_and_exit(FS_OPT_GET_ERROR(status));
+
+ if (fsrv->cmplog_binary && !fsrv->qemu_mode) {
+
+ FATAL("Target was compiled with outdated CMPLOG, recompile it!\n");
+
+ }
+
+ if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
+
+ // workaround for recent AFL++ versions
+ if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) ==
+ FS_OPT_OLD_AFLPP_WORKAROUND)
+ status = (status & 0xf0ffffff);
+
+ if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
+
+ if (fsrv->qemu_mode || fsrv->frida_mode) {
+
+ report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
- FATAL("Writing to forkserver failed.");
+ } else {
+
+ report_error_and_exit(FS_ERROR_OLD_CMPLOG);
}
- if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
+ }
+
+ if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
+
+ fsrv->snapshot = 1;
+ if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
+
+ }
+
+ if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
+
+ if (fsrv->support_shmem_fuzz) {
+
+ fsrv->use_shmem_fuzz = 1;
+ if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
+
+ if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
+
+ 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.");
+
+ }
+
+ }
+
+ } else {
- FATAL("Reading from forkserver failed.");
+ FATAL(
+ "Target requested sharedmem fuzzing, but we failed to enable "
+ "it.");
}
- if (status < 2 || (u32)status > 0xffffff) {
+ }
+
+ if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
+
+ u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
+
+ if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
+
+ fsrv->real_map_size = tmp_map_size;
+
+ if (tmp_map_size % 64) {
- FATAL("Dictionary has an illegal size: %d", status);
+ tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
}
- u32 offset = 0, count = 0;
- u32 len = status;
- u8 *dict = ck_alloc(len);
- if (dict == NULL) {
+ if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
+ if (tmp_map_size > fsrv->map_size) {
- FATAL("Could not allocate %u bytes of autodictionary memory", len);
+ FATAL(
+ "Target's coverage map size of %u is larger than the one this "
+ "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
+ "restart "
+ " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
+ "afl-fuzz",
+ tmp_map_size, fsrv->map_size, tmp_map_size);
}
- while (len != 0) {
+ fsrv->map_size = tmp_map_size;
- rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
- if (rlen > 0) {
+ }
- len -= rlen;
- offset += rlen;
+ if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
+
+ if (!ignore_autodict) {
+
+ if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
+
+ // this is not afl-fuzz - or it is cmplog - we deny and return
+ if (fsrv->use_shmem_fuzz) {
+
+ status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
+
+ } else {
+
+ status = (FS_OPT_ENABLED);
+
+ }
+
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
+
+ FATAL("Writing to forkserver failed.");
+
+ }
+
+ return;
+
+ }
+
+ if (!be_quiet) { ACTF("Using AUTODICT feature."); }
+
+ if (fsrv->use_shmem_fuzz) {
+
+ status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else {
- FATAL(
- "Reading autodictionary fail at position %u with %u bytes "
- "left.",
- offset, len);
+ status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
}
- }
+ if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
- offset = 0;
- while (offset < (u32)status &&
- (u8)dict[offset] + offset < (u32)status) {
+ FATAL("Writing to forkserver failed.");
- fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
- (u8)dict[offset]);
- offset += (1 + dict[offset]);
- count++;
+ }
- }
+ if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
- if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
- ck_free(dict);
+ FATAL("Reading from forkserver failed.");
+
+ }
+
+ if (status < 2 || (u32)status > 0xffffff) {
+
+ FATAL("Dictionary has an illegal size: %d", status);
+
+ }
+
+ u32 offset = 0, count = 0;
+ u32 len = status;
+ u8 *dict = ck_alloc(len);
+ if (dict == NULL) {
+
+ FATAL("Could not allocate %u bytes of autodictionary memory",
+ len);
+
+ }
+
+ while (len != 0) {
+
+ rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
+ if (rlen > 0) {
+
+ len -= rlen;
+ offset += rlen;
+
+ } else {
+
+ FATAL(
+ "Reading autodictionary fail at position %u with %u bytes "
+ "left.",
+ offset, len);
+
+ }
+
+ }
+
+ offset = 0;
+ while (offset < (u32)status &&
+ (u8)dict[offset] + offset < (u32)status) {
+
+ fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
+ (u8)dict[offset]);
+ offset += (1 + dict[offset]);
+ count++;
+
+ }
+
+ if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
+ ck_free(dict);
+
+ }
}
@@ -1226,7 +1486,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n");
} else {
@@ -1271,7 +1531,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf), fsrv->mem_limit << 20),
fsrv->mem_limit - 1);
@@ -1321,7 +1581,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" Retry with setting AFL_MAP_SIZE=10000000.\n\n"
"Otherwise there is a horrible bug in the fuzzer.\n"
- "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n");
+ "Poke the Awesome Fuzzing Discord for troubleshooting tips.\n");
} else {
@@ -1370,7 +1630,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
" - Less likely, there is a horrible bug in the fuzzer. If other "
"options\n"
- " fail, poke <afl-users@googlegroups.com> for troubleshooting "
+ " fail, poke the Awesome Fuzzing Discord for troubleshooting "
"tips.\n",
getenv(DEFER_ENV_VAR)
? " - You are using deferred forkserver, but __AFL_INIT() is "
@@ -1548,6 +1808,11 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
u32 exec_ms;
u32 write_value = fsrv->last_run_timed_out;
+#ifdef AFL_PERSISTENT_RECORD
+ fsrv_run_result_t retval = FSRV_RUN_OK;
+ char *persistent_out_fmt;
+#endif
+
#ifdef __linux__
if (fsrv->nyx_mode) {
@@ -1577,11 +1842,13 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
case Timeout:
return FSRV_RUN_TMOUT;
case InvalidWriteToPayload:
+ if (!!getenv("AFL_NYX_HANDLE_INVALID_WRITE")) { return FSRV_RUN_CRASH; }
+
/* ??? */
FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
break;
case Abort:
- FATAL("Error: Nyx abort occured...");
+ FATAL("Error: Nyx abort occurred...");
case IoError:
if (*stop_soon_p) {
@@ -1595,7 +1862,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
break;
case Error:
- FATAL("Error: Nyx runtime error has occured...");
+ FATAL("Error: Nyx runtime error has occurred...");
break;
}
@@ -1610,7 +1877,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
territory. */
#ifdef __linux__
- if (!fsrv->nyx_mode) {
+ if (likely(!fsrv->nyx_mode)) {
memset(fsrv->trace_bits, 0, fsrv->map_size);
MEM_BARRIER();
@@ -1680,7 +1947,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (exec_ms > timeout) {
- /* If there was no response from forkserver after timeout seconds,
+ /* If there was no response from forkserver after timeout milliseconds,
we kill the child. The forkserver should inform us afterwards */
s32 tmp_pid = fsrv->child_pid;
@@ -1747,6 +2014,18 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
if (unlikely(fsrv->last_run_timed_out)) {
fsrv->last_kill_signal = fsrv->child_kill_signal;
+
+#ifdef AFL_PERSISTENT_RECORD
+ if (unlikely(fsrv->persistent_record)) {
+
+ retval = FSRV_RUN_TMOUT;
+ persistent_out_fmt = "%s/hangs/RECORD:%06u,cnt:%06u%s%s";
+ goto store_persistent_record;
+
+ }
+
+#endif
+
return FSRV_RUN_TMOUT;
}
@@ -1768,48 +2047,66 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
(fsrv->uses_crash_exitcode &&
WEXITSTATUS(fsrv->child_status) == fsrv->crash_exitcode))) {
+ /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
+ fsrv->last_kill_signal =
+ WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
+
#ifdef AFL_PERSISTENT_RECORD
if (unlikely(fsrv->persistent_record)) {
- char fn[PATH_MAX];
- u32 i, writecnt = 0;
- for (i = 0; i < fsrv->persistent_record; ++i) {
+ retval = FSRV_RUN_CRASH;
+ persistent_out_fmt = "%s/crashes/RECORD:%06u,cnt:%06u%s%s";
+ goto store_persistent_record;
- u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
- u8 *data = fsrv->persistent_record_data[entry];
- u32 len = fsrv->persistent_record_len[entry];
- if (likely(len && data)) {
+ }
- snprintf(fn, sizeof(fn), "%s/RECORD:%06u,cnt:%06u",
- fsrv->persistent_record_dir, fsrv->persistent_record_cnt,
- writecnt++);
- int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
- if (fd >= 0) {
+#endif
- ck_write(fd, data, len, fn);
- close(fd);
+ return FSRV_RUN_CRASH;
- }
+ }
- }
+ /* success :) */
+ return FSRV_RUN_OK;
- }
+#ifdef AFL_PERSISTENT_RECORD
+store_persistent_record: {
+
+ char fn[PATH_MAX];
+ u32 i, writecnt = 0;
+ for (i = 0; i < fsrv->persistent_record; ++i) {
+
+ u32 entry = (i + fsrv->persistent_record_idx) % fsrv->persistent_record;
+ u8 *data = fsrv->persistent_record_data[entry];
+ u32 len = fsrv->persistent_record_len[entry];
+ if (likely(len && data)) {
+
+ snprintf(
+ fn, sizeof(fn), persistent_out_fmt, fsrv->persistent_record_dir,
+ fsrv->persistent_record_cnt, writecnt++,
+ ((afl_state_t *)(fsrv->afl_ptr))->file_extension ? "." : "",
+ ((afl_state_t *)(fsrv->afl_ptr))->file_extension
+ ? (const char *)((afl_state_t *)(fsrv->afl_ptr))->file_extension
+ : "");
+ int fd = open(fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+ if (fd >= 0) {
+
+ ck_write(fd, data, len, fn);
+ close(fd);
- ++fsrv->persistent_record_cnt;
+ }
}
-#endif
+ }
- /* For a proper crash, set last_kill_signal to WTERMSIG, else set it to 0 */
- fsrv->last_kill_signal =
- WIFSIGNALED(fsrv->child_status) ? WTERMSIG(fsrv->child_status) : 0;
- return FSRV_RUN_CRASH;
+ ++fsrv->persistent_record_cnt;
- }
+ return retval;
- /* success :) */
- return FSRV_RUN_OK;
+}
+
+#endif
}
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 556bb5d1..03bc5d6c 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -459,6 +459,17 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
+ if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+
+ classify_counts(&afl->fsrv);
+ u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ // Saturated increment
+ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
+ afl->n_fuzz[cksum % N_FUZZ_SIZE]++;
+
+ }
+
return 0;
}
@@ -474,7 +485,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* Generating a hash on every input is super expensive. Bad idea and should
only be used for special schedules */
- if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+ if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
classify_counts(&afl->fsrv);
classified = 1;
@@ -516,23 +527,56 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES
- queue_fn =
- alloc_printf("%s/queue/id:%06u,%s", afl->out_dir, afl->queued_items,
- describe_op(afl, new_bits + is_timeout,
- NAME_MAX - strlen("id:000000,")));
+ if (!afl->afl_env.afl_sha1_filenames) {
+
+ queue_fn = alloc_printf(
+ "%s/queue/id:%06u,%s%s%s", afl->out_dir, afl->queued_items,
+ describe_op(afl, new_bits + is_timeout,
+ NAME_MAX - strlen("id:000000,")),
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+ } else {
+
+ const char *hex = sha1_hex(mem, len);
+ queue_fn = alloc_printf(
+ "%s/queue/%s%s%s", afl->out_dir, hex, afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+ ck_free((char *)hex);
+
+ }
#else
- queue_fn =
- alloc_printf("%s/queue/id_%06u", afl->out_dir, afl->queued_items);
+ queue_fn = alloc_printf(
+ "%s/queue/id_%06u", afl->out_dir, afl->queued_items,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
#endif /* ^!SIMPLE_FILES */
- fd = open(queue_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
- if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", queue_fn); }
- ck_write(fd, mem, len, queue_fn);
- close(fd);
+ fd = permissive_create(afl, queue_fn);
+ if (likely(fd >= 0)) {
+
+ ck_write(fd, mem, len, queue_fn);
+ close(fd);
+
+ }
+
add_to_queue(afl, queue_fn, len, 0);
+ if (unlikely(afl->fuzz_mode) &&
+ likely(afl->switch_fuzz_mode && !afl->non_instrumented_mode)) {
+
+ if (afl->afl_env.afl_no_ui) {
+
+ ACTF("New coverage found, switching back to exploration mode.");
+
+ }
+
+ afl->fuzz_mode = 0;
+
+ }
+
#ifdef INTROSPECTION
if (afl->custom_mutators_count && afl->current_custom_fuzz) {
@@ -715,14 +759,29 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES
- snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s", afl->out_dir,
- afl->saved_hangs,
- describe_op(afl, 0, NAME_MAX - strlen("id:000000,")));
+ if (!afl->afl_env.afl_sha1_filenames) {
+
+ snprintf(fn, PATH_MAX, "%s/hangs/id:%06llu,%s%s%s", afl->out_dir,
+ afl->saved_hangs,
+ describe_op(afl, 0, NAME_MAX - strlen("id:000000,")),
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+ } else {
+
+ const char *hex = sha1_hex(mem, len);
+ snprintf(fn, PATH_MAX, "%s/hangs/%s%s%s", afl->out_dir, hex,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+ ck_free((char *)hex);
+
+ }
#else
- snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu", afl->out_dir,
- afl->saved_hangs);
+ snprintf(fn, PATH_MAX, "%s/hangs/id_%06llu%s%s", afl->out_dir,
+ afl->saved_hangs, afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
#endif /* ^!SIMPLE_FILES */
@@ -768,14 +827,30 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
#ifndef SIMPLE_FILES
- snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s", afl->out_dir,
- afl->saved_crashes, afl->fsrv.last_kill_signal,
- describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")));
+ if (!afl->afl_env.afl_sha1_filenames) {
+
+ snprintf(fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s%s",
+ afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal,
+ describe_op(afl, 0, NAME_MAX - strlen("id:000000,sig:00,")),
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+ } else {
+
+ const char *hex = sha1_hex(mem, len);
+ snprintf(fn, PATH_MAX, "%s/crashes/%s%s%s", afl->out_dir, hex,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+ ck_free((char *)hex);
+
+ }
#else
- snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u", afl->out_dir,
- afl->saved_crashes, afl->fsrv.last_kill_signal);
+ snprintf(fn, PATH_MAX, "%s/crashes/id_%06llu_%02u%s%s", afl->out_dir,
+ afl->saved_crashes, afl->fsrv.last_kill_signal,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
#endif /* ^!SIMPLE_FILES */
@@ -838,10 +913,13 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* If we're here, we apparently want to save the crash or hang
test case, too. */
- fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
- if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn); }
- ck_write(fd, mem, len, fn);
- close(fd);
+ fd = permissive_create(afl, fn);
+ if (fd >= 0) {
+
+ ck_write(fd, mem, len, fn);
+ close(fd);
+
+ }
#ifdef __linux__
if (afl->fsrv.nyx_mode && fault == FSRV_RUN_CRASH) {
@@ -853,7 +931,8 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", fn_log); }
u32 nyx_aux_string_len = afl->fsrv.nyx_handlers->nyx_get_aux_string(
- afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string, 0x1000);
+ afl->fsrv.nyx_runner, afl->fsrv.nyx_aux_string,
+ afl->fsrv.nyx_aux_string_len);
ck_write(fd, afl->fsrv.nyx_aux_string, nyx_aux_string_len, fn_log);
close(fd);
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index 3e6432ca..8c48eb49 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -7,11 +7,11 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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 f6de11ae..55b6be04 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -176,6 +176,8 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
afl->extras =
afl_realloc((void **)&afl->extras,
(afl->extras_cnt + 1) * sizeof(struct extra_data));
+ char *hexdigits = "0123456789abcdef";
+
if (unlikely(!afl->extras)) { PFATAL("alloc"); }
wptr = afl->extras[afl->extras_cnt].data = ck_alloc(rptr - lptr);
@@ -184,13 +186,12 @@ void load_extras_file(afl_state_t *afl, u8 *fname, u32 *min_len, u32 *max_len,
while (*lptr) {
- char *hexdigits = "0123456789abcdef";
-
switch (*lptr) {
case 1 ... 31:
case 128 ... 255:
WARNF("Non-printable characters in line %u.", cur_line);
+ ++lptr;
continue;
break;
@@ -741,8 +742,11 @@ void save_auto(afl_state_t *afl) {
for (i = 0; i < MIN((u32)USE_AUTO_EXTRAS, afl->a_extras_cnt); ++i) {
- u8 *fn =
- alloc_printf("%s/queue/.state/auto_extras/auto_%06u", afl->out_dir, i);
+ u8 *fn = alloc_printf(
+ "%s/queue/.state/auto_extras/auto_%06u%s%s", afl->out_dir, i,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
s32 fd;
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index baf56a5f..7310e49f 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -124,6 +124,9 @@ void bind_to_free_cpu(afl_state_t *afl) {
}
WARNF("Not binding to a CPU core (AFL_NO_AFFINITY set).");
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = 0; }
+ #endif
return;
}
@@ -151,6 +154,9 @@ void bind_to_free_cpu(afl_state_t *afl) {
} else {
OKF("CPU binding request using -b %d successful.", afl->cpu_to_bind);
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode) { afl->fsrv.nyx_bind_cpu_id = afl->cpu_to_bind; }
+ #endif
}
@@ -453,6 +459,24 @@ void bind_to_free_cpu(afl_state_t *afl) {
#endif /* HAVE_AFFINITY */
+/* transforms spaces in a string to underscores (inplace) */
+
+static void no_spaces(u8 *string) {
+
+ if (string) {
+
+ u8 *ptr = string;
+ while (*ptr != 0) {
+
+ if (*ptr == ' ') { *ptr = '_'; }
+ ++ptr;
+
+ }
+
+ }
+
+}
+
/* Shuffle an array of pointers. Might be slightly biased. */
static void shuffle_ptrs(afl_state_t *afl, void **ptrs, u32 cnt) {
@@ -553,6 +577,8 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
afl->stage_cur = 0;
afl->stage_max = 0;
+ show_stats(afl);
+
for (i = 0; i < (u32)nl_cnt; ++i) {
struct stat st;
@@ -631,7 +657,12 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
munmap(mem, st.st_size);
close(fd);
- if (st.st_mtime > mtime_max) mtime_max = st.st_mtime;
+ if (st.st_mtime > mtime_max) {
+
+ mtime_max = st.st_mtime;
+ show_stats(afl);
+
+ }
}
@@ -908,6 +939,14 @@ void perform_dry_run(afl_state_t *afl) {
res = calibrate_case(afl, q, use_mem, 0, 1);
+ /* For AFLFast schedules we update the queue entry */
+ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE) &&
+ likely(q->exec_cksum)) {
+
+ q->n_fuzz_entry = q->exec_cksum % N_FUZZ_SIZE;
+
+ }
+
if (afl->stop_soon) { return; }
if (res == afl->crash_mode || res == FSRV_RUN_NOBITS) {
@@ -942,6 +981,7 @@ void perform_dry_run(afl_state_t *afl) {
if (!q->was_fuzzed) {
q->was_fuzzed = 1;
+ afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
@@ -951,19 +991,48 @@ void perform_dry_run(afl_state_t *afl) {
} else {
- SAYF("\n" cLRD "[-] " cRST
- "The program took more than %u ms to process one of the initial "
- "test cases.\n"
- " This is bad news; raising the limit with the -t option is "
- "possible, but\n"
- " will probably make the fuzzing process extremely slow.\n\n"
+ static int say_once = 0;
+
+ if (!say_once) {
+
+ SAYF(
+ "\n" cLRD "[-] " cRST
+ "The program took more than %u ms to process one of the "
+ "initial "
+ "test cases.\n"
+ " This is bad news; raising the limit with the -t option is "
+ "possible, but\n"
+ " will probably make the fuzzing process extremely slow.\n\n"
+
+ " If this test case is just a fluke, the other option is to "
+ "just avoid it\n"
+ " altogether, and find one that is less of a CPU hog.\n",
+ afl->fsrv.exec_tmout);
+
+ if (!afl->afl_env.afl_ignore_seed_problems) {
+
+ FATAL("Test case '%s' results in a timeout", fn);
- " If this test case is just a fluke, the other option is to "
- "just avoid it\n"
- " altogether, and find one that is less of a CPU hog.\n",
- afl->fsrv.exec_tmout);
+ }
- FATAL("Test case '%s' results in a timeout", fn);
+ say_once = 1;
+
+ }
+
+ if (!q->was_fuzzed) {
+
+ q->was_fuzzed = 1;
+ afl->reinit_table = 1;
+ --afl->pending_not_fuzzed;
+ --afl->active_items;
+
+ }
+
+ q->disabled = 1;
+ q->perf_score = 0;
+
+ WARNF("Test case '%s' results in a timeout, skipping", fn);
+ break;
}
@@ -1012,7 +1081,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
- " fail, poke <afl-users@googlegroups.com> for "
+ " fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n",
stringify_mem_size(val_buf, sizeof(val_buf),
afl->fsrv.mem_limit << 20),
@@ -1041,7 +1110,7 @@ void perform_dry_run(afl_state_t *afl) {
" - Least likely, there is a horrible bug in the fuzzer. If "
"other options\n"
- " fail, poke <afl-users@googlegroups.com> for "
+ " fail, poke the Awesome Fuzzing Discord for "
"troubleshooting tips.\n");
}
@@ -1058,7 +1127,19 @@ void perform_dry_run(afl_state_t *afl) {
} else {
- WARNF("Test case '%s' results in a crash, skipping", fn);
+ if (afl->afl_env.afl_crashing_seeds_as_new_crash) {
+
+ WARNF(
+ "Test case '%s' results in a crash, "
+ "as AFL_CRASHING_SEEDS_AS_NEW_CRASH is set, "
+ "saving as a new crash",
+ fn);
+
+ } else {
+
+ WARNF("Test case '%s' results in a crash, skipping", fn);
+
+ }
}
@@ -1073,41 +1154,118 @@ void perform_dry_run(afl_state_t *afl) {
if (!q->was_fuzzed) {
q->was_fuzzed = 1;
+ afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
}
- q->disabled = 1;
- q->perf_score = 0;
+ /* Crashing seeds will be regarded as new crashes on startup */
+ if (afl->afl_env.afl_crashing_seeds_as_new_crash) {
- u32 i = 0;
- while (unlikely(i < afl->queued_items && afl->queue_buf[i] &&
- afl->queue_buf[i]->disabled)) {
+ ++afl->total_crashes;
- ++i;
+ if (likely(!afl->non_instrumented_mode)) {
- }
+ classify_counts(&afl->fsrv);
+
+ simplify_trace(afl, afl->fsrv.trace_bits);
+
+ if (!has_new_bits(afl, afl->virgin_crash)) { break; }
+
+ }
+
+ if (unlikely(!afl->saved_crashes) &&
+ (afl->afl_env.afl_no_crash_readme != 1)) {
- if (i < afl->queued_items && afl->queue_buf[i]) {
+ write_crash_readme(afl);
- afl->queue = afl->queue_buf[i];
+ }
+
+ u8 crash_fn[PATH_MAX];
+ u8 *use_name = strstr(q->fname, ",orig:");
+
+ afl->stage_name = "dry_run";
+ afl->stage_short = "dry_run";
+
+#ifndef SIMPLE_FILES
+
+ if (!afl->afl_env.afl_sha1_filenames) {
+
+ snprintf(
+ crash_fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%s%s%s%s",
+ afl->out_dir, afl->saved_crashes, afl->fsrv.last_kill_signal,
+ describe_op(
+ afl, 0,
+ NAME_MAX - strlen("id:000000,sig:00,") - strlen(use_name)),
+ use_name, afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+ } else {
+
+ const char *hex = sha1_hex(use_mem, read_len);
+ snprintf(
+ crash_fn, PATH_MAX, "%s/crashes/%s%s%s", afl->out_dir, hex,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+ ck_free((char *)hex);
+
+ }
+
+#else
+
+ snprintf(
+ crash_fn, PATH_MAX, "%s/crashes/id_%06llu_%02u%s%s", afl->out_dir,
+ afl->saved_crashes, afl->fsrv.last_kill_signal,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+#endif
+
+ ++afl->saved_crashes;
+
+ fd = open(crash_fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
+ if (unlikely(fd < 0)) { PFATAL("Unable to create '%s'", crash_fn); }
+ ck_write(fd, use_mem, read_len, crash_fn);
+ close(fd);
+
+ afl->last_crash_time = get_cur_time();
+ afl->last_crash_execs = afl->fsrv.total_execs;
} else {
- afl->queue = afl->queue_buf[0];
+ u32 i = 0;
+ while (unlikely(i < afl->queued_items && afl->queue_buf[i] &&
+ afl->queue_buf[i]->disabled)) {
- }
+ ++i;
+
+ }
+
+ if (i < afl->queued_items && afl->queue_buf[i]) {
+
+ afl->queue = afl->queue_buf[i];
+
+ } else {
+
+ afl->queue = afl->queue_buf[0];
+
+ }
+
+ afl->max_depth = 0;
+ for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
- afl->max_depth = 0;
- for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
+ if (!afl->queue_buf[i]->disabled &&
+ afl->queue_buf[i]->depth > afl->max_depth)
+ afl->max_depth = afl->queue_buf[i]->depth;
- if (!afl->queue_buf[i]->disabled &&
- afl->queue_buf[i]->depth > afl->max_depth)
- afl->max_depth = afl->queue_buf[i]->depth;
+ }
}
+ q->disabled = 1;
+ q->perf_score = 0;
+
break;
case FSRV_RUN_ERROR:
@@ -1192,6 +1350,7 @@ void perform_dry_run(afl_state_t *afl) {
if (!p->was_fuzzed) {
p->was_fuzzed = 1;
+ afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
@@ -1212,6 +1371,7 @@ void perform_dry_run(afl_state_t *afl) {
if (!q->was_fuzzed) {
q->was_fuzzed = 1;
+ afl->reinit_table = 1;
--afl->pending_not_fuzzed;
--afl->active_items;
@@ -1262,11 +1422,11 @@ void perform_dry_run(afl_state_t *afl) {
static void link_or_copy(u8 *old_path, u8 *new_path) {
s32 i = link(old_path, new_path);
+ if (!i) { return; }
+
s32 sfd, dfd;
u8 *tmp;
- if (!i) { return; }
-
sfd = open(old_path, O_RDONLY);
if (sfd < 0) { PFATAL("Unable to open '%s'", old_path); }
@@ -1329,7 +1489,9 @@ void pivot_inputs(afl_state_t *afl) {
u32 src_id;
afl->resuming_fuzz = 1;
- nfn = alloc_printf("%s/queue/%s", afl->out_dir, rsl);
+ nfn = alloc_printf(
+ "%s/queue/%s%s%s", afl->out_dir, rsl, afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
/* Since we're at it, let's also get the parent and figure out the
appropriate depth for this entry. */
@@ -1369,12 +1531,33 @@ void pivot_inputs(afl_state_t *afl) {
}
- nfn = alloc_printf("%s/queue/id:%06u,time:0,execs:%llu,orig:%s",
- afl->out_dir, id, afl->fsrv.total_execs, use_name);
+ if (!afl->afl_env.afl_sha1_filenames) {
+
+ nfn = alloc_printf(
+ "%s/queue/id:%06u,time:0,execs:%llu,orig:%s%s%s", afl->out_dir, id,
+ afl->fsrv.total_execs, use_name, afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+
+ } else {
+
+ const char *hex = sha1_hex_for_file(q->fname, q->len);
+ nfn = alloc_printf(
+ "%s/queue/%s%s%s", afl->out_dir, hex,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
+ ck_free((char *)hex);
+
+ }
+
+ u8 *pos = strrchr(nfn, '/');
+ no_spaces(pos + 30);
#else
- nfn = alloc_printf("%s/queue/id_%06u", afl->out_dir, id);
+ nfn = alloc_printf(
+ "%s/queue/id_%06u%s%s", afl->out_dir, id,
+ afl->file_extension ? "." : "",
+ afl->file_extension ? (const char *)afl->file_extension : "");
#endif /* ^!SIMPLE_FILES */
@@ -1542,8 +1725,8 @@ double get_runnable_processes(void) {
processes well. */
FILE *f = fopen("/proc/stat", "r");
- u8 tmp[1024];
- u32 val = 0;
+ u8 tmp[1024];
+ u32 val = 0;
if (!f) { return 0; }
@@ -1581,10 +1764,11 @@ double get_runnable_processes(void) {
void nuke_resume_dir(afl_state_t *afl) {
- u8 *fn;
+ u8 *const case_prefix = afl->afl_env.afl_sha1_filenames ? "" : CASE_PREFIX;
+ u8 *fn;
fn = alloc_printf("%s/_resume/.state/deterministic_done", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/_resume/.state/auto_extras", afl->out_dir);
@@ -1592,11 +1776,11 @@ void nuke_resume_dir(afl_state_t *afl) {
ck_free(fn);
fn = alloc_printf("%s/_resume/.state/redundant_edges", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/_resume/.state/variable_behavior", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/_resume/.state", afl->out_dir);
@@ -1604,7 +1788,7 @@ void nuke_resume_dir(afl_state_t *afl) {
ck_free(fn);
fn = alloc_printf("%s/_resume", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
return;
@@ -1621,8 +1805,9 @@ dir_cleanup_failed:
static void handle_existing_out_dir(afl_state_t *afl) {
- FILE *f;
- u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
+ u8 *const case_prefix = afl->afl_env.afl_sha1_filenames ? "" : CASE_PREFIX;
+ FILE *f;
+ u8 *fn = alloc_printf("%s/fuzzer_stats", afl->out_dir);
/* See if the output directory is locked. If yes, bail out. If not,
create a lock that will persist for the lifetime of the process
@@ -1744,7 +1929,7 @@ static void handle_existing_out_dir(afl_state_t *afl) {
/* Next, we need to clean up <afl->out_dir>/queue/.state/ subdirectories: */
fn = alloc_printf("%s/queue/.state/deterministic_done", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/queue/.state/auto_extras", afl->out_dir);
@@ -1752,11 +1937,11 @@ static void handle_existing_out_dir(afl_state_t *afl) {
ck_free(fn);
fn = alloc_printf("%s/queue/.state/redundant_edges", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/queue/.state/variable_behavior", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
/* Then, get rid of the .state subdirectory itself (should be empty by now)
@@ -1767,7 +1952,7 @@ static void handle_existing_out_dir(afl_state_t *afl) {
ck_free(fn);
fn = alloc_printf("%s/queue", afl->out_dir);
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
/* All right, let's do <afl->out_dir>/crashes/id:* and
@@ -1811,7 +1996,10 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+#ifdef AFL_PERSISTENT_RECORD
+ delete_files(fn, RECORD_PREFIX);
+#endif
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
fn = alloc_printf("%s/hangs", afl->out_dir);
@@ -1843,7 +2031,10 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
- if (delete_files(fn, CASE_PREFIX)) { goto dir_cleanup_failed; }
+#ifdef AFL_PERSISTENT_RECORD
+ delete_files(fn, RECORD_PREFIX);
+#endif
+ if (delete_files(fn, case_prefix)) { goto dir_cleanup_failed; }
ck_free(fn);
/* And now, for some finishing touches. */
@@ -2126,6 +2317,21 @@ void setup_dirs_fds(afl_state_t *afl) {
fflush(afl->fsrv.plot_file);
+#ifdef INTROSPECTION
+
+ tmp = alloc_printf("%s/plot_det_data", afl->out_dir);
+
+ int fd = open(tmp, O_WRONLY | O_CREAT, DEFAULT_PERMISSION);
+ if (fd < 0) { PFATAL("Unable to create '%s'", tmp); }
+ ck_free(tmp);
+
+ afl->fsrv.det_plot_file = fdopen(fd, "w");
+ if (!afl->fsrv.det_plot_file) { PFATAL("fdopen() failed"); }
+
+ if (afl->in_place_resume) { fseek(afl->fsrv.det_plot_file, 0, SEEK_END); }
+
+#endif
+
/* ignore errors */
}
@@ -2199,7 +2405,8 @@ void check_crash_handling(void) {
reporting the awful way. */
#if !TARGET_OS_IPHONE
- if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash$'")) return;
+ if (system("launchctl list 2>/dev/null | grep -q '\\.ReportCrash\\>'"))
+ return;
SAYF(
"\n" cLRD "[-] " cRST
@@ -2226,7 +2433,7 @@ void check_crash_handling(void) {
*BSD, so we can just let it slide for now. */
s32 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY);
- u8 fchar;
+ u8 fchar;
if (fd < 0) { return; }
@@ -2365,7 +2572,7 @@ void check_cpu_governor(afl_state_t *afl) {
FATAL("Suboptimal CPU scaling governor");
#elif defined __APPLE__
- u64 min = 0, max = 0;
+ u64 min = 0, max = 0;
size_t mlen = sizeof(min);
if (afl->afl_env.afl_skip_cpufreq) return;
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index 64dbe7c6..2f6af4bc 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -5,12 +5,12 @@
Originally written by Shengtuo Hu
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -397,6 +397,18 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
}
+ /* "afl_custom_post_run", optional */
+ mutator->afl_custom_post_run = dlsym(dh, "afl_custom_post_run");
+ if (!mutator->afl_custom_post_run) {
+
+ ACTF("optional symbol 'afl_custom_post_run' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_post_run'.");
+
+ }
+
/* "afl_custom_queue_new_entry", optional */
mutator->afl_custom_queue_new_entry = dlsym(dh, "afl_custom_queue_new_entry");
if (!mutator->afl_custom_queue_new_entry) {
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index c6e9a295..74bb8cbc 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -27,6 +27,7 @@
#include <string.h>
#include <limits.h>
#include "cmplog.h"
+#include "afl-mutations.h"
/* MOpt */
@@ -70,50 +71,6 @@ static int select_algorithm(afl_state_t *afl, u32 max_algorithm) {
}
-/* Helper to choose random block len for block operations in fuzz_one().
- Doesn't return zero, provided that max_len is > 0. */
-
-static inline u32 choose_block_len(afl_state_t *afl, u32 limit) {
-
- u32 min_value, max_value;
- u32 rlim = MIN(afl->queue_cycle, (u32)3);
-
- if (unlikely(!afl->run_over10m)) { rlim = 1; }
-
- switch (rand_below(afl, rlim)) {
-
- case 0:
- min_value = 1;
- max_value = HAVOC_BLK_SMALL;
- break;
-
- case 1:
- min_value = HAVOC_BLK_SMALL;
- max_value = HAVOC_BLK_MEDIUM;
- break;
-
- default:
-
- if (likely(rand_below(afl, 10))) {
-
- min_value = HAVOC_BLK_MEDIUM;
- max_value = HAVOC_BLK_LARGE;
-
- } else {
-
- min_value = HAVOC_BLK_LARGE;
- max_value = HAVOC_BLK_XL;
-
- }
-
- }
-
- if (min_value >= limit) { min_value = 1; }
-
- return min_value + rand_below(afl, MIN(max_value, limit) - min_value + 1);
-
-}
-
/* Helper function to see if a particular change (xor_val = old ^ new) could
be a product of deterministic bit flips with the lengths and stepovers
attempted by afl-fuzz. This is used to avoid dupes in some of the
@@ -372,9 +329,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
u32 len, temp_len;
u32 j;
u32 i;
- u8 *in_buf, *out_buf, *orig_in, *ex_tmp, *eff_map = 0;
+ u8 *in_buf, *out_buf, *orig_in, *ex_tmp;
u64 havoc_queued = 0, orig_hit_cnt, new_hit_cnt = 0, prev_cksum, _prev_cksum;
- u32 splice_cycle = 0, perf_score = 100, orig_perf, eff_cnt = 1;
+ u32 splice_cycle = 0, perf_score = 100, orig_perf;
u8 ret_val = 1, doing_det = 0;
@@ -442,18 +399,24 @@ u8 fuzz_one_original(afl_state_t *afl) {
#endif /* ^IGNORE_FINDS */
- if (unlikely(afl->not_on_tty)) {
+ if (likely(afl->not_on_tty)) {
+
+ u8 time_tmp[64];
+ u_simplestring_time_diff(time_tmp, afl->prev_run_time + get_cur_time(),
+ afl->start_time);
ACTF(
- "Fuzzing test case #%u (%u total, %llu crashes saved, "
+ "Fuzzing test case #%u (%u total, %llu crashes saved, state: %s, "
+ "mode=%s, "
"perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
- "exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
+ "exec_us=%llu, hits=%u, map=%u, ascii=%u, run_time=%s)...",
afl->current_entry, afl->queued_items, afl->saved_crashes,
+ get_fuzzing_state(afl), afl->fuzz_mode ? "exploit" : "explore",
afl->queue_cur->perf_score, afl->queue_cur->weight,
afl->queue_cur->favored, afl->queue_cur->was_fuzzed,
afl->queue_cur->exec_us,
likely(afl->n_fuzz) ? afl->n_fuzz[afl->queue_cur->n_fuzz_entry] : 0,
- afl->queue_cur->bitmap_size, afl->queue_cur->is_ascii);
+ afl->queue_cur->bitmap_size, afl->queue_cur->is_ascii, time_tmp);
fflush(stdout);
}
@@ -582,12 +545,37 @@ u8 fuzz_one_original(afl_state_t *afl) {
}
+ u64 before_det_time = get_cur_time();
+#ifdef INTROSPECTION
+
+ u64 before_havoc_time;
+ u32 before_det_findings = afl->queued_items,
+ before_det_edges = count_non_255_bytes(afl, afl->virgin_bits),
+ before_havoc_findings, before_havoc_edges;
+ u8 is_logged = 0;
+
+#endif
+ if (!afl->skip_deterministic) {
+
+ if (!skip_deterministic_stage(afl, in_buf, out_buf, len, before_det_time)) {
+
+ goto abandon_entry;
+
+ }
+
+ }
+
+ u8 *skip_eff_map = afl->queue_cur->skipdet_e->skip_eff_map;
+
/* Skip right away if -d is given, if it has not been chosen sufficiently
often to warrant the expensive deterministic stage (fuzz_level), or
if it has gone through deterministic testing in earlier, resumed runs
(passed_det). */
+ /* if skipdet decide to skip the seed or no interesting bytes found,
+ we skip the whole deterministic stage as well */
if (likely(afl->skip_deterministic) || likely(afl->queue_cur->passed_det) ||
+ likely(!afl->queue_cur->skipdet_e->quick_eff_bytes) ||
likely(perf_score <
(afl->queue_cur->depth * 30 <= afl->havoc_max_mult * 100
? afl->queue_cur->depth * 30
@@ -614,13 +602,13 @@ u8 fuzz_one_original(afl_state_t *afl) {
* SIMPLE BITFLIP (+dictionary construction) *
*********************************************/
-#define FLIP_BIT(_ar, _b) \
- do { \
- \
- u8 *_arf = (u8 *)(_ar); \
- u32 _bf = (_b); \
- _arf[(_bf) >> 3] ^= (128 >> ((_bf)&7)); \
- \
+#define FLIP_BIT(_ar, _b) \
+ do { \
+ \
+ u8 *_arf = (u8 *)(_ar); \
+ u32 _bf = (_b); \
+ _arf[(_bf) >> 3] ^= (128 >> ((_bf) & 7)); \
+ \
} while (0)
/* Single walking bit. */
@@ -646,6 +634,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_cur_byte = afl->stage_cur >> 3;
+ if (!skip_eff_map[afl->stage_cur_byte]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
FLIP_BIT(out_buf, afl->stage_cur);
#ifdef INTROSPECTION
@@ -762,6 +754,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_cur_byte = afl->stage_cur >> 3;
+ if (!skip_eff_map[afl->stage_cur_byte]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
FLIP_BIT(out_buf, afl->stage_cur);
FLIP_BIT(out_buf, afl->stage_cur + 1);
@@ -797,6 +793,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_cur_byte = afl->stage_cur >> 3;
+ if (!skip_eff_map[afl->stage_cur_byte]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
FLIP_BIT(out_buf, afl->stage_cur);
FLIP_BIT(out_buf, afl->stage_cur + 1);
FLIP_BIT(out_buf, afl->stage_cur + 2);
@@ -824,34 +824,6 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->queue_cur->stats_mutated += afl->stage_max;
#endif
- /* Effector map setup. These macros calculate:
-
- EFF_APOS - position of a particular file offset in the map.
- EFF_ALEN - length of a map with a particular number of bytes.
- EFF_SPAN_ALEN - map span for a sequence of bytes.
-
- */
-
-#define EFF_APOS(_p) ((_p) >> EFF_MAP_SCALE2)
-#define EFF_REM(_x) ((_x) & ((1 << EFF_MAP_SCALE2) - 1))
-#define EFF_ALEN(_l) (EFF_APOS(_l) + !!EFF_REM(_l))
-#define EFF_SPAN_ALEN(_p, _l) (EFF_APOS((_p) + (_l)-1) - EFF_APOS(_p) + 1)
-
- /* Initialize effector map for the next step (see comments below). Always
- flag first and last byte as doing something. */
-
- eff_map = afl_realloc(AFL_BUF_PARAM(eff), EFF_ALEN(len));
- if (unlikely(!eff_map)) { PFATAL("alloc"); }
- memset(eff_map, 0, EFF_ALEN(len));
- eff_map[0] = 1;
-
- if (EFF_APOS(len - 1) != 0) {
-
- eff_map[EFF_APOS(len - 1)] = 1;
- ++eff_cnt;
-
- }
-
/* Walking byte. */
afl->stage_name = "bitflip 8/8";
@@ -865,6 +837,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_cur_byte = afl->stage_cur;
+ if (!skip_eff_map[afl->stage_cur_byte]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
out_buf[afl->stage_cur] ^= 0xFF;
#ifdef INTROSPECTION
@@ -874,59 +850,19 @@ u8 fuzz_one_original(afl_state_t *afl) {
if (common_fuzz_stuff(afl, out_buf, len)) { goto abandon_entry; }
- /* We also use this stage to pull off a simple trick: we identify
- bytes that seem to have no effect on the current execution path
- even when fully flipped - and we skip them during more expensive
- deterministic stages, such as arithmetics or known ints. */
-
- if (!eff_map[EFF_APOS(afl->stage_cur)]) {
-
- u64 cksum;
-
- /* If in non-instrumented mode or if the file is very short, just flag
- everything without wasting time on checksums. */
-
- if (!afl->non_instrumented_mode && len >= EFF_MIN_LEN) {
-
- cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
-
- } else {
-
- cksum = ~prev_cksum;
-
- }
-
- if (cksum != prev_cksum) {
-
- eff_map[EFF_APOS(afl->stage_cur)] = 1;
- ++eff_cnt;
-
- }
-
- }
-
out_buf[afl->stage_cur] ^= 0xFF;
}
- /* If the effector map is more than EFF_MAX_PERC dense, just flag the
- whole thing as worth fuzzing, since we wouldn't be saving much time
- anyway. */
+ /* New effective bytes calculation. */
- if (eff_cnt != (u32)EFF_ALEN(len) &&
- eff_cnt * 100 / EFF_ALEN(len) > EFF_MAX_PERC) {
+ for (i = 0; i < len; i++) {
- memset(eff_map, 1, EFF_ALEN(len));
-
- afl->blocks_eff_select += EFF_ALEN(len);
-
- } else {
-
- afl->blocks_eff_select += eff_cnt;
+ if (skip_eff_map[i]) afl->blocks_eff_select += 1;
}
- afl->blocks_eff_total += EFF_ALEN(len);
+ afl->blocks_eff_total += len;
new_hit_cnt = afl->queued_items + afl->saved_crashes;
@@ -951,12 +887,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+ if (!skip_eff_map[i]) continue;
- --afl->stage_max;
- continue;
-
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -996,13 +929,10 @@ u8 fuzz_one_original(afl_state_t *afl) {
for (i = 0; i < len - 3; ++i) {
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
- !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
- --afl->stage_max;
- continue;
+ if (!skip_eff_map[i]) continue;
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1053,12 +983,9 @@ skip_bitflip:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)]) {
-
- afl->stage_max -= 2 * ARITH_MAX;
- continue;
+ if (!skip_eff_map[i]) continue;
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1140,12 +1067,9 @@ skip_bitflip:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
-
- afl->stage_max -= 4 * ARITH_MAX;
- continue;
+ if (!skip_eff_map[i]) continue;
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1273,13 +1197,9 @@ skip_bitflip:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
- !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
+ if (!skip_eff_map[i]) continue;
- afl->stage_max -= 4 * ARITH_MAX;
- continue;
-
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1411,12 +1331,9 @@ skip_arith:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)]) {
-
- afl->stage_max -= sizeof(interesting_8);
- continue;
+ if (!skip_eff_map[i]) continue;
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1474,12 +1391,9 @@ skip_arith:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)]) {
+ if (!skip_eff_map[i]) continue;
- afl->stage_max -= sizeof(interesting_16);
- continue;
-
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1565,13 +1479,9 @@ skip_arith:
/* Let's consult the effector map... */
- if (!eff_map[EFF_APOS(i)] && !eff_map[EFF_APOS(i + 1)] &&
- !eff_map[EFF_APOS(i + 2)] && !eff_map[EFF_APOS(i + 3)]) {
-
- afl->stage_max -= sizeof(interesting_32) >> 1;
- continue;
+ if (!skip_eff_map[i]) continue;
- }
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
afl->stage_cur_byte = i;
@@ -1663,6 +1573,10 @@ skip_interest:
u32 last_len = 0;
+ if (!skip_eff_map[i]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
afl->stage_cur_byte = i;
/* Extras are sorted by size, from smallest to largest. This means
@@ -1680,9 +1594,7 @@ skip_interest:
if ((afl->extras_cnt > afl->max_det_extras &&
rand_below(afl, afl->extras_cnt) >= afl->max_det_extras) ||
afl->extras[j].len > len - i ||
- !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len) ||
- !memchr(eff_map + EFF_APOS(i), 1,
- EFF_SPAN_ALEN(i, afl->extras[j].len))) {
+ !memcmp(afl->extras[j].data, out_buf + i, afl->extras[j].len)) {
--afl->stage_max;
continue;
@@ -1730,6 +1642,10 @@ skip_interest:
for (i = 0; i <= (u32)len; ++i) {
+ if (!skip_eff_map[i % len]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
afl->stage_cur_byte = i;
for (j = 0; j < afl->extras_cnt; ++j) {
@@ -1792,6 +1708,10 @@ skip_user_extras:
u32 last_len = 0;
+ if (!skip_eff_map[i]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
afl->stage_cur_byte = i;
u32 min_extra_len = MIN(afl->a_extras_cnt, (u32)USE_AUTO_EXTRAS);
@@ -1800,9 +1720,7 @@ skip_user_extras:
/* See the comment in the earlier code; extras are sorted by size. */
if (afl->a_extras[j].len > len - i ||
- !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len) ||
- !memchr(eff_map + EFF_APOS(i), 1,
- EFF_SPAN_ALEN(i, afl->a_extras[j].len))) {
+ !memcmp(afl->a_extras[j].data, out_buf + i, afl->a_extras[j].len)) {
--afl->stage_max;
continue;
@@ -1850,6 +1768,10 @@ skip_user_extras:
for (i = 0; i <= (u32)len; ++i) {
+ if (!skip_eff_map[i % len]) continue;
+
+ if (is_det_timeout(before_det_time, 0)) { goto custom_mutator_stage; }
+
afl->stage_cur_byte = i;
for (j = 0; j < afl->a_extras_cnt; ++j) {
@@ -1912,6 +1834,7 @@ custom_mutator_stage:
afl->stage_name = "custom mutator";
afl->stage_short = "custom";
+ afl->stage_cur = 0;
afl->stage_val_type = STAGE_VAL_NONE;
bool has_custom_fuzz = false;
u32 shift = unlikely(afl->custom_only) ? 7 : 8;
@@ -1931,6 +1854,8 @@ custom_mutator_stage:
if (el->afl_custom_fuzz) {
+ havoc_queued = afl->queued_items;
+
afl->current_custom_fuzz = el;
afl->stage_name = el->name_short;
@@ -2054,6 +1979,19 @@ custom_mutator_stage:
havoc_stage:
+#ifdef INTROSPECTION
+
+ if (!is_logged) {
+
+ is_logged = 1;
+ before_havoc_findings = afl->queued_items;
+ before_havoc_edges = count_non_255_bytes(afl, afl->virgin_bits);
+ before_havoc_time = get_cur_time();
+
+ }
+
+#endif
+
if (unlikely(afl->custom_only)) {
/* Force UI update */
@@ -2122,45 +2060,97 @@ 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 64
-#define MUTATE_ASCII_DICT 64
+ u32 *mutation_array;
+ u32 stack_max, rand_max; // stack_max_pow = afl->havoc_stack_pow2;
+
+ switch (afl->input_mode) {
+
+ case 1: { // TEXT
- u32 r_max, r;
+ if (likely(afl->fuzz_mode == 0)) { // is exploration?
+ mutation_array = (unsigned int *)&binary_array;
+ rand_max = MUT_BIN_ARRAY_SIZE;
- r_max = (MAX_HAVOC_ENTRY + 1) + (afl->extras_cnt ? 4 : 0) +
- (afl->a_extras_cnt
- ? (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)
- ? MUTATE_ASCII_DICT
- : 4)
- : 0);
+ } else { // exploitation mode
- if (unlikely(afl->expand_havoc && afl->ready_for_splicing_count > 1)) {
+ mutation_array = (unsigned int *)&text_array;
+ rand_max = MUT_TXT_ARRAY_SIZE;
- /* add expensive havoc cases here, they are activated after a full
- cycle without finds happened */
+ }
+
+ break;
+
+ }
+
+ case 2: { // BINARY
+
+ if (likely(afl->fuzz_mode == 0)) { // is exploration?
+ mutation_array = (unsigned int *)&mutation_strategy_exploration_binary;
+ rand_max = MUT_STRATEGY_ARRAY_SIZE;
+
+ } else { // exploitation mode
+
+ mutation_array = (unsigned int *)&mutation_strategy_exploitation_binary;
+ rand_max = MUT_STRATEGY_ARRAY_SIZE;
+ // or this one? we do not have enough binary bug benchmarks :-(
+ // mutation_array = (unsigned int *)&binary_array;
+ // rand_max = MUT_BIN_ARRAY_SIZE;
+
+ }
+
+ break;
+
+ }
+
+ default: { // DEFAULT/GENERIC
- r_max += 4;
+ if (likely(afl->fuzz_mode == 0)) { // is exploration?
+ mutation_array = (unsigned int *)&binary_array;
+ rand_max = MUT_BIN_ARRAY_SIZE;
+
+ } else { // exploitation mode
+
+ mutation_array = (unsigned int *)&text_array;
+ rand_max = MUT_TXT_ARRAY_SIZE;
+
+ }
+
+ break;
+
+ }
}
- if (unlikely(get_cur_time() - afl->last_find_time > 5000 /* 5 seconds */ &&
- afl->ready_for_splicing_count > 1)) {
+ /*
+ if (temp_len < 64) {
+
+ --stack_max_pow;
- /* add expensive havoc cases here if there is no findings in the last 5s */
+ } else if (temp_len <= 8096) {
- r_max += 4;
+ ++stack_max_pow;
+
+ } else {
+
+ ++stack_max_pow;
}
+ */
+
+ stack_max = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2));
+
+ // + (afl->extras_cnt ? 2 : 0) + (afl->a_extras_cnt ? 2 : 0);
+
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
- u32 use_stacking = 1 << (1 + rand_below(afl, afl->havoc_stack_pow2));
+ u32 use_stacking = 1 + rand_below(afl, stack_max);
afl->stage_cur_val = use_stacking;
#ifdef INTROSPECTION
- snprintf(afl->mutation, sizeof(afl->mutation), "%s HAVOC-%u",
- afl->queue_cur->fname, use_stacking);
+ snprintf(afl->mutation, sizeof(afl->mutation), "%s HAVOC-%u-%u",
+ afl->queue_cur->fname, afl->queue_cur->is_ascii, use_stacking);
#endif
for (i = 0; i < use_stacking; ++i) {
@@ -2169,8 +2159,8 @@ havoc_stage:
LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
- if (el->stacked_custom &&
- rand_below(afl, 100) < el->stacked_custom_prob) {
+ if (unlikely(el->stacked_custom &&
+ rand_below(afl, 100) < el->stacked_custom_prob)) {
u8 *custom_havoc_buf = NULL;
size_t new_len = el->afl_custom_havoc_mutation(
@@ -2200,159 +2190,173 @@ havoc_stage:
}
- switch ((r = rand_below(afl, r_max))) {
+ retry_havoc_step: {
+
+ u32 r = rand_below(afl, rand_max), item;
+
+ switch (mutation_array[r]) {
- case 0 ... 3: {
+ case MUT_FLIPBIT: {
/* Flip a single bit somewhere. Spooky! */
+ u8 bit = rand_below(afl, 8);
+ u32 off = rand_below(afl, temp_len);
+ out_buf[off] ^= 1 << bit;
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP_BIT1");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP-BIT_%u", bit);
strcat(afl->mutation, afl->m_tmp);
#endif
- FLIP_BIT(out_buf, rand_below(afl, temp_len << 3));
break;
}
- case 4 ... 7: {
+ case MUT_INTERESTING8: {
/* Set byte to interesting value. */
+ item = rand_below(afl, sizeof(interesting_8));
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING8_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- out_buf[rand_below(afl, temp_len)] =
- interesting_8[rand_below(afl, sizeof(interesting_8))];
+ out_buf[rand_below(afl, temp_len)] = interesting_8[item];
break;
}
- case 8 ... 9: {
+ case MUT_INTERESTING16: {
/* Set word to interesting value, little endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
+ item = rand_below(afl, sizeof(interesting_16) >> 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
+
*(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
- interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)];
+ interesting_16[item];
break;
}
- case 10 ... 11: {
+ case MUT_INTERESTING16BE: {
/* Set word to interesting value, big endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
+ item = rand_below(afl, sizeof(interesting_16) >> 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING16BE_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) = SWAP16(
- interesting_16[rand_below(afl, sizeof(interesting_16) >> 1)]);
+ *(u16 *)(out_buf + rand_below(afl, temp_len - 1)) =
+ SWAP16(interesting_16[item]);
break;
}
- case 12 ... 13: {
+ case MUT_INTERESTING32: {
/* Set dword to interesting value, little endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
+ item = rand_below(afl, sizeof(interesting_32) >> 2);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
+
*(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
- interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)];
+ interesting_32[item];
break;
}
- case 14 ... 15: {
+ case MUT_INTERESTING32BE: {
/* Set dword to interesting value, big endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
+ item = rand_below(afl, sizeof(interesting_32) >> 2);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INTERESTING32BE_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) = SWAP32(
- interesting_32[rand_below(afl, sizeof(interesting_32) >> 2)]);
+ *(u32 *)(out_buf + rand_below(afl, temp_len - 3)) =
+ SWAP32(interesting_32[item]);
break;
}
- case 16 ... 19: {
+ case MUT_ARITH8_: {
/* Randomly subtract from byte. */
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8_");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8-_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- out_buf[rand_below(afl, temp_len)] -= 1 + rand_below(afl, ARITH_MAX);
+ out_buf[rand_below(afl, temp_len)] -= item;
break;
}
- case 20 ... 23: {
+ case MUT_ARITH8: {
/* Randomly add to byte. */
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH8+_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- out_buf[rand_below(afl, temp_len)] += 1 + rand_below(afl, ARITH_MAX);
+ out_buf[rand_below(afl, temp_len)] += item;
break;
}
- case 24 ... 25: {
+ case MUT_ARITH16_: {
/* Randomly subtract from word, little endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 1);
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_-%u", pos);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16-_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u16 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+ *(u16 *)(out_buf + pos) -= item;
break;
}
- case 26 ... 27: {
+ case MUT_ARITH16BE_: {
/* Randomly subtract from word, big endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 1);
u16 num = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16_BE-%u_%u", pos,
- num);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE-_%u", num);
strcat(afl->mutation, afl->m_tmp);
#endif
*(u16 *)(out_buf + pos) =
@@ -2362,36 +2366,36 @@ havoc_stage:
}
- case 28 ... 29: {
+ case MUT_ARITH16: {
/* Randomly add to word, little endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 1);
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+-%u", pos);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u16 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+ *(u16 *)(out_buf + pos) += item;
break;
}
- case 30 ... 31: {
+ case MUT_ARITH16BE: {
/* Randomly add to word, big endian. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 1);
u16 num = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16+BE-%u_%u", pos,
- num);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH16BE+__%u", num);
strcat(afl->mutation, afl->m_tmp);
#endif
*(u16 *)(out_buf + pos) =
@@ -2401,36 +2405,36 @@ havoc_stage:
}
- case 32 ... 33: {
+ case MUT_ARITH32_: {
/* Randomly subtract from dword, little endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 3);
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_-%u", pos);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32-_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u32 *)(out_buf + pos) -= 1 + rand_below(afl, ARITH_MAX);
+ *(u32 *)(out_buf + pos) -= item;
break;
}
- case 34 ... 35: {
+ case MUT_ARITH32BE_: {
/* Randomly subtract from dword, big endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 3);
u32 num = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32_BE-%u-%u", pos,
- num);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE-_%u", num);
strcat(afl->mutation, afl->m_tmp);
#endif
*(u32 *)(out_buf + pos) =
@@ -2440,36 +2444,36 @@ havoc_stage:
}
- case 36 ... 37: {
+ case MUT_ARITH32: {
/* Randomly add to dword, little endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 3);
+ item = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+-%u", pos);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+_%u", item);
strcat(afl->mutation, afl->m_tmp);
#endif
- *(u32 *)(out_buf + pos) += 1 + rand_below(afl, ARITH_MAX);
+ *(u32 *)(out_buf + pos) += item;
break;
}
- case 38 ... 39: {
+ case MUT_ARITH32BE: {
/* Randomly add to dword, big endian. */
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
u32 pos = rand_below(afl, temp_len - 3);
u32 num = 1 + rand_below(afl, ARITH_MAX);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32+BE-%u-%u", pos,
- num);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ARITH32BE+_%u", num);
strcat(afl->mutation, afl->m_tmp);
#endif
*(u32 *)(out_buf + pos) =
@@ -2479,24 +2483,27 @@ havoc_stage:
}
- case 40 ... 43: {
+ case MUT_RAND8: {
/* Just set a random byte to a random value. Because,
why not. We use XOR with 1-255 to eliminate the
possibility of a no-op. */
+ u32 pos = rand_below(afl, temp_len);
+ item = 1 + rand_below(afl, 255);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " RAND8_%u",
+ out_buf[pos] ^ item);
strcat(afl->mutation, afl->m_tmp);
#endif
- out_buf[rand_below(afl, temp_len)] ^= 1 + rand_below(afl, 255);
+ out_buf[pos] ^= item;
break;
}
- case 44 ... 46: {
+ case MUT_CLONE_COPY: {
- if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+ if (likely(temp_len + HAVOC_BLK_XL < MAX_FILE)) {
/* Clone bytes. */
@@ -2505,8 +2512,8 @@ havoc_stage:
u32 clone_to = rand_below(afl, temp_len);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u-%u",
- "clone", clone_from, clone_to, clone_len);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s_%u_%u_%u",
+ "COPY", clone_from, clone_to, clone_len);
strcat(afl->mutation, afl->m_tmp);
#endif
u8 *new_buf =
@@ -2529,24 +2536,35 @@ havoc_stage:
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
temp_len += clone_len;
+ } else if (unlikely(temp_len < 8)) {
+
+ break;
+
+ } else {
+
+ goto retry_havoc_step;
+
}
break;
}
- case 47: {
+ case MUT_CLONE_FIXED: {
- if (temp_len + HAVOC_BLK_XL < MAX_FILE) {
+ if (likely(temp_len + HAVOC_BLK_XL < MAX_FILE)) {
/* Insert a block of constant bytes (25%). */
u32 clone_len = choose_block_len(afl, HAVOC_BLK_XL);
u32 clone_to = rand_below(afl, temp_len);
+ u32 strat = rand_below(afl, 2);
+ u32 clone_from = clone_to ? clone_to - 1 : 0;
+ item = strat ? rand_below(afl, 256) : out_buf[clone_from];
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s-%u-%u",
- "insert", clone_to, clone_len);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " CLONE-%s_%u_%u_%u",
+ "FIXED", strat, clone_to, clone_len);
strcat(afl->mutation, afl->m_tmp);
#endif
u8 *new_buf =
@@ -2559,10 +2577,7 @@ havoc_stage:
/* Inserted part */
- memset(new_buf + clone_to,
- rand_below(afl, 2) ? rand_below(afl, 256)
- : out_buf[rand_below(afl, temp_len)],
- clone_len);
+ memset(new_buf + clone_to, item, clone_len);
/* Tail */
memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
@@ -2572,66 +2587,77 @@ havoc_stage:
afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
temp_len += clone_len;
+ } else if (unlikely(temp_len < 8)) {
+
+ break;
+
+ } else {
+
+ goto retry_havoc_step;
+
}
break;
}
- case 48 ... 50: {
+ case MUT_OVERWRITE_COPY: {
/* Overwrite bytes with a randomly selected chunk bytes. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
- u32 copy_len = choose_block_len(afl, temp_len - 1);
- u32 copy_from = rand_below(afl, temp_len - copy_len + 1);
- u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
+ u32 copy_from, copy_to,
+ copy_len = choose_block_len(afl, temp_len - 1);
- if (likely(copy_from != copy_to)) {
+ do {
+
+ copy_from = rand_below(afl, temp_len - copy_len + 1);
+ copy_to = rand_below(afl, temp_len - copy_len + 1);
+
+ } while (unlikely(copy_from == copy_to));
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_COPY-%u-%u-%u",
- copy_from, copy_to, copy_len);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE-COPY_%u_%u_%u",
+ copy_from, copy_to, copy_len);
+ strcat(afl->mutation, afl->m_tmp);
#endif
- memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
-
- }
+ memmove(out_buf + copy_to, out_buf + copy_from, copy_len);
break;
}
- case 51: {
+ case MUT_OVERWRITE_FIXED: {
/* Overwrite bytes with fixed bytes. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
u32 copy_len = choose_block_len(afl, temp_len - 1);
u32 copy_to = rand_below(afl, temp_len - copy_len + 1);
+ u32 strat = rand_below(afl, 2);
+ u32 copy_from = copy_to ? copy_to - 1 : 0;
+ item = strat ? rand_below(afl, 256) : out_buf[copy_from];
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " OVERWRITE_FIXED-%u-%u",
- copy_to, copy_len);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " OVERWRITE-FIXED_%u_%u_%u-%u", strat, item, copy_to,
+ copy_len);
strcat(afl->mutation, afl->m_tmp);
#endif
- memset(out_buf + copy_to,
- rand_below(afl, 2) ? rand_below(afl, 256)
- : out_buf[rand_below(afl, temp_len)],
- copy_len);
+ memset(out_buf + copy_to, item, copy_len);
break;
}
- case 52: {
+ case MUT_BYTEADD: {
/* Increase byte by 1. */
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ADDBYTE_");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " BYTEADD_");
strcat(afl->mutation, afl->m_tmp);
#endif
out_buf[rand_below(afl, temp_len)]++;
@@ -2639,12 +2665,12 @@ havoc_stage:
}
- case 53: {
+ case MUT_BYTESUB: {
/* Decrease byte by 1. */
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SUBBYTE_");
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " BYTESUB_");
strcat(afl->mutation, afl->m_tmp);
#endif
out_buf[rand_below(afl, temp_len)]--;
@@ -2652,9 +2678,9 @@ havoc_stage:
}
- case 54: {
+ case MUT_FLIP8: {
- /* Flip byte. */
+ /* Flip byte with a XOR 0xff. This is the same as NEG. */
#ifdef INTROSPECTION
snprintf(afl->m_tmp, sizeof(afl->m_tmp), " FLIP8_");
@@ -2665,9 +2691,9 @@ havoc_stage:
}
- case 55 ... 56: {
+ case MUT_SWITCH: {
- if (temp_len < 4) { break; }
+ if (unlikely(temp_len < 4)) { break; } // no retry
/* Switch bytes. */
@@ -2677,7 +2703,7 @@ havoc_stage:
switch_to = rand_below(afl, temp_len);
- } while (switch_from == switch_to);
+ } while (unlikely(switch_from == switch_to));
if (switch_from < switch_to) {
@@ -2694,7 +2720,7 @@ havoc_stage:
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",
+ 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
@@ -2717,12 +2743,11 @@ havoc_stage:
}
- // MAX_HAVOC_ENTRY = 64
- case 57 ... MAX_HAVOC_ENTRY: {
+ case MUT_DEL: {
/* Delete bytes. */
- if (temp_len < 2) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
/* Don't delete too much. */
@@ -2730,7 +2755,7 @@ havoc_stage:
u32 del_from = rand_below(afl, temp_len - del_len + 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL-%u-%u", del_from,
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DEL_%u_%u", del_from,
del_len);
strcat(afl->mutation, afl->m_tmp);
#endif
@@ -2743,135 +2768,401 @@ havoc_stage:
}
- default:
+ case MUT_SHUFFLE: {
- r -= (MAX_HAVOC_ENTRY + 1);
+ /* Shuffle bytes. */
- if (afl->extras_cnt) {
+ if (unlikely(temp_len < 4)) { break; } // no retry
- if (r < 2) {
+ u32 len = choose_block_len(afl, temp_len - 1);
+ u32 off = rand_below(afl, temp_len - len + 1);
- /* Use the dictionary. */
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SHUFFLE_%u", len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ for (u32 i = len - 1; i > 0; i--) {
+
+ u32 j;
+ do {
+
+ j = rand_below(afl, i + 1);
+
+ } while (unlikely(i == j));
- u32 use_extra = rand_below(afl, afl->extras_cnt);
- u32 extra_len = afl->extras[use_extra].len;
+ unsigned char temp = out_buf[off + i];
+ out_buf[off + i] = out_buf[off + j];
+ out_buf[off + j] = temp;
- if (extra_len > temp_len) { break; }
+ }
+
+ break;
+
+ }
+
+ case MUT_DELONE: {
+
+ /* Delete bytes. */
+
+ if (unlikely(temp_len < 2)) { break; } // no retry
+
+ /* Don't delete too much. */
+
+ u32 del_len = 1;
+ u32 del_from = rand_below(afl, temp_len - del_len + 1);
- u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_OVERWRITE-%u-%u",
- insert_at, extra_len);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " DELONE_%u", del_from);
+ strcat(afl->mutation, afl->m_tmp);
#endif
- memcpy(out_buf + insert_at, afl->extras[use_extra].data,
- extra_len);
+ memmove(out_buf + del_from, out_buf + del_from + del_len,
+ temp_len - del_from - del_len);
- break;
+ temp_len -= del_len;
+
+ break;
+
+ }
- } else if (r < 4) {
+ case MUT_INSERTONE: {
- u32 use_extra = rand_below(afl, afl->extras_cnt);
- u32 extra_len = afl->extras[use_extra].len;
- if (temp_len + extra_len >= MAX_FILE) { break; }
+ if (unlikely(temp_len < 2)) { break; } // no retry
+
+ u32 clone_len = 1;
+ u32 clone_to = rand_below(afl, temp_len);
+ u32 strat = rand_below(afl, 2);
+ u32 clone_from = clone_to ? clone_to - 1 : 0;
+ item = strat ? rand_below(afl, 256) : out_buf[clone_from];
- u8 *ptr = afl->extras[use_extra].data;
- u32 insert_at = rand_below(afl, temp_len + 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA_INSERT-%u-%u",
- insert_at, extra_len);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INSERTONE_%u_%u", strat,
+ clone_to);
+ strcat(afl->mutation, afl->m_tmp);
#endif
+ u8 *new_buf =
+ afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
- out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
- if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ /* Head */
- /* Tail */
- memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
- temp_len - insert_at);
+ memcpy(new_buf, out_buf, clone_to);
- /* Inserted part */
- memcpy(out_buf + insert_at, ptr, extra_len);
- temp_len += extra_len;
+ /* Inserted part */
- break;
+ memset(new_buf + clone_to, item, clone_len);
- } else {
+ /* Tail */
+ memcpy(new_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
- r -= 4;
+ out_buf = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
- }
+ break;
+
+ }
+
+ case MUT_ASCIINUM: {
+
+ if (unlikely(temp_len < 4)) { break; } // no retry
+
+ u32 off = rand_below(afl, temp_len), off2 = off, cnt = 0;
+
+ while (off2 + cnt < temp_len && !isdigit(out_buf[off2 + cnt])) {
+
+ ++cnt;
}
- if (afl->a_extras_cnt) {
+ // none found, wrap
+ if (off2 + cnt == temp_len) {
- u32 r_cmp = 2;
+ off2 = 0;
+ cnt = 0;
- if (unlikely(afl->cmplog_binary && afl->queue_cur->is_ascii)) {
+ while (cnt < off && !isdigit(out_buf[off2 + cnt])) {
- r_cmp = MUTATE_ASCII_DICT >> 1;
+ ++cnt;
}
- if (r < r_cmp) {
+ if (cnt == off) {
- /* Use the dictionary. */
+ if (temp_len < 8) {
- u32 use_extra = rand_below(afl, afl->a_extras_cnt);
- u32 extra_len = afl->a_extras[use_extra].len;
+ break;
- if (extra_len > temp_len) { break; }
+ } else {
- u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
-#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp),
- " AUTO_EXTRA_OVERWRITE-%u-%u", insert_at, extra_len);
- strcat(afl->mutation, afl->m_tmp);
-#endif
- memcpy(out_buf + insert_at, afl->a_extras[use_extra].data,
- extra_len);
+ goto retry_havoc_step;
+
+ }
+
+ }
+
+ }
+
+ off = off2 + cnt;
+ off2 = off + 1;
+
+ while (off2 < temp_len && isdigit(out_buf[off2])) {
+
+ ++off2;
+
+ }
+ s64 val = out_buf[off] - '0';
+ for (u32 i = off + 1; i < off2; ++i) {
+
+ val = (val * 10) + out_buf[i] - '0';
+
+ }
+
+ if (off && out_buf[off - 1] == '-') { val = -val; }
+
+ u32 strat = rand_below(afl, 8);
+ switch (strat) {
+
+ case 0:
+ val++;
+ break;
+ case 1:
+ val--;
+ break;
+ case 2:
+ val *= 2;
+ break;
+ case 3:
+ val /= 2;
break;
+ case 4:
+ if (likely(val && (u64)val < 0x19999999)) {
- } else if (r < (r_cmp << 1)) {
+ val = (u64)rand_next(afl) % (u64)((u64)val * 10);
+
+ } else {
- u32 use_extra = rand_below(afl, afl->a_extras_cnt);
- u32 extra_len = afl->a_extras[use_extra].len;
- if (temp_len + extra_len >= MAX_FILE) { break; }
+ val = rand_below(afl, 256);
+
+ }
+
+ break;
+ case 5:
+ val += rand_below(afl, 256);
+ break;
+ case 6:
+ val -= rand_below(afl, 256);
+ break;
+ case 7:
+ val = ~(val);
+ break;
+
+ }
- u8 *ptr = afl->a_extras[use_extra].data;
- u32 insert_at = rand_below(afl, temp_len + 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp),
- " AUTO_EXTRA_INSERT-%u-%u", insert_at, extra_len);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " ASCIINUM_%u_%u_%u",
+ afl->queue_cur->is_ascii, strat, off);
+ strcat(afl->mutation, afl->m_tmp);
#endif
+ // fprintf(stderr, "val: %u-%u = %ld\n", off, off2, val);
+
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%" PRId64, val);
- out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
- if (unlikely(!out_buf)) { PFATAL("alloc"); }
+ // fprintf(stderr, "BEFORE: %s\n", out_buf);
- /* Tail */
- memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
- temp_len - insert_at);
+ u32 old_len = off2 - off;
+ u32 new_len = strlen(buf);
- /* Inserted part */
- memcpy(out_buf + insert_at, ptr, extra_len);
- temp_len += extra_len;
+ if (old_len == new_len) {
+
+ memcpy(out_buf + off, buf, new_len);
+
+ } else {
+
+ u8 *new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
+ temp_len + new_len - old_len);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+
+ /* Head */
+
+ memcpy(new_buf, out_buf, off);
+
+ /* Inserted part */
+
+ memcpy(new_buf + off, buf, new_len);
+
+ /* Tail */
+ memcpy(new_buf + off + new_len, out_buf + off2, temp_len - off2);
+
+ out_buf = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += (new_len - old_len);
+
+ }
+
+ // fprintf(stderr, "AFTER : %s\n", out_buf);
+ break;
+
+ }
+
+ case MUT_INSERTASCIINUM: {
+
+ u32 len = 1 + rand_below(afl, 8);
+ u32 pos = rand_below(afl, temp_len);
+ /* Insert ascii number. */
+ if (unlikely(temp_len < pos + len)) {
+
+ if (unlikely(temp_len < 8)) {
break;
} else {
- r -= (r_cmp << 1);
+ goto retry_havoc_step;
}
}
- /* Splicing otherwise if we are still here.
- Overwrite bytes with a randomly selected chunk from another
- testcase or insert that chunk. */
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " INSERTASCIINUM_");
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ u64 val = rand_next(afl);
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%llu", val);
+ memcpy(out_buf + pos, buf, len);
+
+ break;
+
+ }
+
+ case MUT_EXTRA_OVERWRITE: {
+
+ if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
+
+ /* Use the dictionary. */
+
+ u32 use_extra = rand_below(afl, afl->extras_cnt);
+ u32 extra_len = afl->extras[use_extra].len;
+
+ if (unlikely(extra_len > temp_len)) { goto retry_havoc_step; }
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA-OVERWRITE_%u_%u",
+ insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->extras[use_extra].data, extra_len);
+
+ break;
+
+ }
+
+ case MUT_EXTRA_INSERT: {
+
+ if (unlikely(!afl->extras_cnt)) { goto retry_havoc_step; }
+
+ u32 use_extra = rand_below(afl, afl->extras_cnt);
+ u32 extra_len = afl->extras[use_extra].len;
+ if (unlikely(temp_len + extra_len >= MAX_FILE)) {
+
+ goto retry_havoc_step;
+
+ }
+
+ u8 *ptr = afl->extras[use_extra].data;
+ u32 insert_at = rand_below(afl, temp_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " EXTRA-INSERT_%u_%u",
+ insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ /* Tail */
+ memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+ temp_len - insert_at);
+
+ /* Inserted part */
+ memcpy(out_buf + insert_at, ptr, extra_len);
+ temp_len += extra_len;
+
+ break;
+
+ }
+
+ case MUT_AUTO_EXTRA_OVERWRITE: {
+
+ if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
+
+ /* Use the dictionary. */
+
+ u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+ u32 extra_len = afl->a_extras[use_extra].len;
+
+ if (unlikely(extra_len > temp_len)) { goto retry_havoc_step; }
+
+ u32 insert_at = rand_below(afl, temp_len - extra_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " AUTO-EXTRA-OVERWRITE_%u_%u", insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+ memcpy(out_buf + insert_at, afl->a_extras[use_extra].data, extra_len);
+
+ break;
+
+ }
+
+ case MUT_AUTO_EXTRA_INSERT: {
+
+ if (unlikely(!afl->a_extras_cnt)) { goto retry_havoc_step; }
+
+ u32 use_extra = rand_below(afl, afl->a_extras_cnt);
+ u32 extra_len = afl->a_extras[use_extra].len;
+ if (unlikely(temp_len + extra_len >= MAX_FILE)) {
+
+ goto retry_havoc_step;
+
+ }
+
+ u8 *ptr = afl->a_extras[use_extra].data;
+ u32 insert_at = rand_below(afl, temp_len + 1);
+#ifdef INTROSPECTION
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " AUTO-EXTRA-INSERT_%u_%u",
+ insert_at, extra_len);
+ strcat(afl->mutation, afl->m_tmp);
+#endif
+
+ out_buf = afl_realloc(AFL_BUF_PARAM(out), temp_len + extra_len);
+ if (unlikely(!out_buf)) { PFATAL("alloc"); }
+
+ /* Tail */
+ memmove(out_buf + insert_at + extra_len, out_buf + insert_at,
+ temp_len - insert_at);
+
+ /* Inserted part */
+ memcpy(out_buf + insert_at, ptr, extra_len);
+ temp_len += extra_len;
+
+ break;
+
+ }
+
+ case MUT_SPLICE_OVERWRITE: {
+
+ if (unlikely(afl->ready_for_splicing_count <= 1)) {
+
+ goto retry_havoc_step;
+
+ }
/* Pick a random queue entry and seek to it. */
@@ -2880,79 +3171,110 @@ havoc_stage:
tid = rand_below(afl, afl->queued_items);
- } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+ } while (unlikely(tid == afl->current_entry ||
+
+ afl->queue_buf[tid]->len < 4));
/* Get the testcase for splicing. */
struct queue_entry *target = afl->queue_buf[tid];
u32 new_len = target->len;
u8 *new_buf = queue_testcase_get(afl, target);
- if ((temp_len >= 2 && r % 2) || temp_len + HAVOC_BLK_XL >= MAX_FILE) {
-
- /* overwrite mode */
+ /* overwrite mode */
- u32 copy_from, copy_to, copy_len;
+ u32 copy_from, copy_to, copy_len;
- copy_len = choose_block_len(afl, new_len - 1);
- if (copy_len > temp_len) copy_len = temp_len;
+ copy_len = choose_block_len(afl, new_len - 1);
+ if (copy_len > temp_len) copy_len = temp_len;
- copy_from = rand_below(afl, new_len - copy_len + 1);
- copy_to = rand_below(afl, temp_len - copy_len + 1);
+ copy_from = rand_below(afl, new_len - copy_len + 1);
+ copy_to = rand_below(afl, temp_len - copy_len + 1);
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp),
- " SPLICE_OVERWRITE-%u-%u-%u-%s", copy_from, copy_to,
- copy_len, target->fname);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp),
+ " SPLICE-OVERWRITE_%u_%u_%u_%s", copy_from, copy_to,
+ copy_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
#endif
- memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
+ memmove(out_buf + copy_to, new_buf + copy_from, copy_len);
- } else {
+ break;
+
+ }
+
+ case MUT_SPLICE_INSERT: {
+
+ if (unlikely(afl->ready_for_splicing_count <= 1)) {
+
+ goto retry_havoc_step;
+
+ }
+
+ if (unlikely(temp_len + HAVOC_BLK_XL >= MAX_FILE)) {
+
+ goto retry_havoc_step;
+
+ }
+
+ /* Pick a random queue entry and seek to it. */
+
+ u32 tid;
+ do {
+
+ tid = rand_below(afl, afl->queued_items);
+
+ } while (unlikely(tid == afl->current_entry ||
+
+ afl->queue_buf[tid]->len < 4));
- /* insert mode */
+ /* Get the testcase for splicing. */
+ struct queue_entry *target = afl->queue_buf[tid];
+ u32 new_len = target->len;
+ u8 *new_buf = queue_testcase_get(afl, target);
- u32 clone_from, clone_to, clone_len;
+ /* insert mode */
- clone_len = choose_block_len(afl, new_len);
- clone_from = rand_below(afl, new_len - clone_len + 1);
- clone_to = rand_below(afl, temp_len + 1);
+ u32 clone_from, clone_to, clone_len;
- u8 *temp_buf = afl_realloc(AFL_BUF_PARAM(out_scratch),
- temp_len + clone_len + 1);
- if (unlikely(!temp_buf)) { PFATAL("alloc"); }
+ clone_len = choose_block_len(afl, new_len);
+ clone_from = rand_below(afl, new_len - clone_len + 1);
+ clone_to = rand_below(afl, temp_len + 1);
+
+ u8 *temp_buf =
+ afl_realloc(AFL_BUF_PARAM(out_scratch), temp_len + clone_len + 1);
+ if (unlikely(!temp_buf)) { PFATAL("alloc"); }
#ifdef INTROSPECTION
- snprintf(afl->m_tmp, sizeof(afl->m_tmp),
- " SPLICE_INSERT-%u-%u-%u-%s", clone_from, clone_to,
- clone_len, target->fname);
- strcat(afl->mutation, afl->m_tmp);
+ snprintf(afl->m_tmp, sizeof(afl->m_tmp), " SPLICE-INSERT_%u_%u_%u_%s",
+ clone_from, clone_to, clone_len, target->fname);
+ strcat(afl->mutation, afl->m_tmp);
#endif
- /* Head */
+ /* Head */
- memcpy(temp_buf, out_buf, clone_to);
+ memcpy(temp_buf, out_buf, clone_to);
- /* Inserted part */
-
- memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
+ /* Inserted part */
- /* Tail */
- memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
- temp_len - clone_to);
+ memcpy(temp_buf + clone_to, new_buf + clone_from, clone_len);
- out_buf = temp_buf;
- afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
- temp_len += clone_len;
+ /* Tail */
+ memcpy(temp_buf + clone_to + clone_len, out_buf + clone_to,
+ temp_len - clone_to);
- }
+ out_buf = temp_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+ temp_len += clone_len;
break;
- // end of default
+ }
}
}
+ }
+
if (common_fuzz_stuff(afl, out_buf, temp_len)) { goto abandon_entry; }
/* out_buf might have been mangled a bit, so let's restore it to its
@@ -3038,7 +3360,9 @@ retry_splicing:
tid = rand_below(afl, afl->queued_items);
- } while (tid == afl->current_entry || afl->queue_buf[tid]->len < 4);
+ } while (
+
+ unlikely(tid == afl->current_entry || afl->queue_buf[tid]->len < 4));
/* Get the testcase */
afl->splicing_with = tid;
@@ -3078,6 +3402,25 @@ retry_splicing:
ret_val = 0;
+#ifdef INTROSPECTION
+
+ afl->havoc_prof->queued_det_stage =
+ before_havoc_findings - before_det_findings;
+ afl->havoc_prof->queued_havoc_stage =
+ afl->queued_items - before_havoc_findings;
+ afl->havoc_prof->total_queued_det += afl->havoc_prof->queued_det_stage;
+ afl->havoc_prof->edge_det_stage = before_havoc_edges - before_det_edges;
+ afl->havoc_prof->edge_havoc_stage =
+ count_non_255_bytes(afl, afl->virgin_bits) - before_havoc_edges;
+ afl->havoc_prof->total_det_edge += afl->havoc_prof->edge_det_stage;
+ afl->havoc_prof->det_stage_time = before_havoc_time - before_det_time;
+ afl->havoc_prof->havoc_stage_time = get_cur_time() - before_havoc_time;
+ afl->havoc_prof->total_det_time += afl->havoc_prof->det_stage_time;
+
+ plot_profile_data(afl, afl->queue_cur);
+
+#endif
+
/* we are through with this queue entry - for this iteration */
abandon_entry:
@@ -3092,7 +3435,12 @@ abandon_entry:
--afl->pending_not_fuzzed;
afl->queue_cur->was_fuzzed = 1;
afl->reinit_table = 1;
- if (afl->queue_cur->favored) { --afl->pending_favored; }
+ if (afl->queue_cur->favored) {
+
+ --afl->pending_favored;
+ afl->smallest_favored = -1;
+
+ }
}
@@ -3348,13 +3696,13 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
* SIMPLE BITFLIP (+dictionary construction) *
*********************************************/
-#define FLIP_BIT(_ar, _b) \
- do { \
- \
- u8 *_arf = (u8 *)(_ar); \
- u32 _bf = (_b); \
- _arf[(_bf) >> 3] ^= (128 >> ((_bf)&7)); \
- \
+#define FLIP_BIT(_ar, _b) \
+ do { \
+ \
+ u8 *_arf = (u8 *)(_ar); \
+ u32 _bf = (_b); \
+ _arf[(_bf) >> 3] ^= (128 >> ((_bf) & 7)); \
+ \
} while (0)
/* Single walking bit. */
@@ -5555,7 +5903,13 @@ pacemaker_fuzzing:
--afl->pending_not_fuzzed;
afl->queue_cur->was_fuzzed = 1;
- if (afl->queue_cur->favored) { --afl->pending_favored; }
+ afl->reinit_table = 1
+ if (afl->queue_cur->favored) {
+
+ --afl->pending_favored;
+ afl->smallest_favored = -1;
+
+ }
}
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index 7dad0770..873b25e2 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -249,6 +249,8 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "queue_get");
py_functions[PY_FUNC_FUZZ_SEND] =
PyObject_GetAttrString(py_module, "fuzz_send");
+ py_functions[PY_FUNC_POST_RUN] =
+ PyObject_GetAttrString(py_module, "post_run");
py_functions[PY_FUNC_SPLICE_OPTOUT] =
PyObject_GetAttrString(py_module, "splice_optout");
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
@@ -468,6 +470,12 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
}
+ if (py_functions[PY_FUNC_POST_RUN]) {
+
+ mutator->afl_custom_post_run = post_run_py;
+
+ }
+
if (py_functions[PY_FUNC_SPLICE_OPTOUT]) {
mutator->afl_custom_splice_optout = splice_optout_py;
@@ -925,6 +933,28 @@ void fuzz_send_py(void *py_mutator, const u8 *buf, size_t buf_size) {
}
+void post_run_py(void *py_mutator) {
+
+ PyObject *py_args, *py_value;
+
+ py_args = PyTuple_New(0);
+ py_value = PyObject_CallObject(
+ ((py_mutator_t *)py_mutator)->py_functions[PY_FUNC_POST_RUN], py_args);
+ Py_DECREF(py_args);
+
+ if (py_value != NULL) {
+
+ Py_DECREF(py_value);
+
+ } else {
+
+ PyErr_Print();
+ FATAL("Call failed");
+
+ }
+
+}
+
u8 queue_new_entry_py(void *py_mutator, const u8 *filename_new_queue,
const u8 *filename_orig_queue) {
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index b10bf749..2318df60 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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:
@@ -80,6 +80,7 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
if (unlikely(weight < 0.1)) { weight = 0.1; }
if (unlikely(q->favored)) { weight *= 5; }
if (unlikely(!q->was_fuzzed)) { weight *= 2; }
+ if (unlikely(q->fs_redundant)) { weight *= 0.8; }
return weight;
@@ -369,9 +370,9 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
s32 fd;
- fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
- if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
- close(fd);
+ if (unlikely(afl->afl_env.afl_disable_redundant)) { q->disabled = 1; }
+ fd = permissive_create(afl, fn);
+ if (fd >= 0) { close(fd); }
} else {
@@ -612,7 +613,7 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
- if (likely(q->len > 4)) afl->ready_for_splicing_count++;
+ if (likely(q->len > 4)) { ++afl->ready_for_splicing_count; }
++afl->queued_items;
++afl->active_items;
@@ -663,6 +664,8 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
+ q->skipdet_e = (struct skipdet_entry *)ck_alloc(sizeof(struct skipdet_entry));
+
}
/* Destroy the entire queue. */
@@ -678,6 +681,15 @@ void destroy_queue(afl_state_t *afl) {
q = afl->queue_buf[i];
ck_free(q->fname);
ck_free(q->trace_mini);
+ if (q->skipdet_e) {
+
+ if (q->skipdet_e->done_inf_map) ck_free(q->skipdet_e->done_inf_map);
+ if (q->skipdet_e->skip_eff_map) ck_free(q->skipdet_e->skip_eff_map);
+
+ ck_free(q->skipdet_e);
+
+ }
+
ck_free(q);
}
@@ -701,13 +713,20 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
u64 fav_factor;
u64 fuzz_p2;
- if (unlikely(afl->schedule >= FAST && afl->schedule < RARE))
+ if (likely(afl->schedule >= FAST && afl->schedule < RARE)) {
+
fuzz_p2 = 0; // Skip the fuzz_p2 comparison
- else if (unlikely(afl->schedule == RARE))
+
+ } else if (unlikely(afl->schedule == RARE)) {
+
fuzz_p2 = next_pow2(afl->n_fuzz[q->n_fuzz_entry]);
- else
+
+ } else {
+
fuzz_p2 = q->fuzz_level;
+ }
+
if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
fav_factor = q->len << 2;
@@ -729,47 +748,36 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
/* Faster-executing or smaller test cases are favored. */
u64 top_rated_fav_factor;
u64 top_rated_fuzz_p2;
- if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE))
- top_rated_fuzz_p2 =
- next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]);
- else
- top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level;
-
- if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
-
- top_rated_fav_factor = afl->top_rated[i]->len << 2;
- } else {
-
- top_rated_fav_factor =
- afl->top_rated[i]->exec_us * afl->top_rated[i]->len;
+ if (likely(afl->schedule >= FAST && afl->schedule < RARE)) {
- }
+ top_rated_fuzz_p2 = 0; // Skip the fuzz_p2 comparison
- if (fuzz_p2 > top_rated_fuzz_p2) {
+ } else if (unlikely(afl->schedule == RARE)) {
- continue;
+ top_rated_fuzz_p2 =
+ next_pow2(afl->n_fuzz[afl->top_rated[i]->n_fuzz_entry]);
- } else if (fuzz_p2 == top_rated_fuzz_p2) {
+ } else {
- if (fav_factor > top_rated_fav_factor) { continue; }
+ top_rated_fuzz_p2 = afl->top_rated[i]->fuzz_level;
}
if (unlikely(afl->schedule >= RARE) || unlikely(afl->fixed_seed)) {
- if (fav_factor > afl->top_rated[i]->len << 2) { continue; }
+ top_rated_fav_factor = afl->top_rated[i]->len << 2;
} else {
- if (fav_factor >
- afl->top_rated[i]->exec_us * afl->top_rated[i]->len) {
+ top_rated_fav_factor =
+ afl->top_rated[i]->exec_us * afl->top_rated[i]->len;
- continue;
+ }
- }
+ if (likely(fuzz_p2 > top_rated_fuzz_p2)) { continue; }
- }
+ if (likely(fav_factor > top_rated_fav_factor)) { continue; }
/* Looks like we're going to win. Decrease ref count for the
previous winner, discard its afl->fsrv.trace_bits[] if necessary. */
@@ -834,6 +842,8 @@ void cull_queue(afl_state_t *afl) {
/* Let's see if anything in the bitmap isn't captured in temp_v.
If yes, and if it has a afl->top_rated[] contender, let's use it. */
+ afl->smallest_favored = -1;
+
for (i = 0; i < afl->fsrv.map_size; ++i) {
if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) {
@@ -857,7 +867,16 @@ void cull_queue(afl_state_t *afl) {
afl->top_rated[i]->favored = 1;
++afl->queued_favored;
- if (!afl->top_rated[i]->was_fuzzed) { ++afl->pending_favored; }
+ if (!afl->top_rated[i]->was_fuzzed) {
+
+ ++afl->pending_favored;
+ if (unlikely(afl->smallest_favored < 0)) {
+
+ afl->smallest_favored = (s64)afl->top_rated[i]->id;
+
+ }
+
+ }
}
@@ -875,6 +894,8 @@ void cull_queue(afl_state_t *afl) {
}
+ afl->reinit_table = 1;
+
}
/* Calculate case desirability score to adjust the length of havoc fuzzing.
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 6e4a655b..9316da71 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -7,7 +7,7 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
@@ -28,8 +28,9 @@
#include "afl-fuzz.h"
#include "cmplog.h"
-//#define _DEBUG
-//#define CMPLOG_INTROSPECTION
+// #define _DEBUG
+// #define USE_HASHMAP
+// #define CMPLOG_INTROSPECTION
// CMP attribute enum
enum {
@@ -40,7 +41,7 @@ enum {
IS_FP = 8, // is a floating point, not an integer
/* --- below are internal settings, not from target cmplog */
IS_FP_MOD = 16, // arithemtic changed floating point
- IS_INT_MOD = 32, // arithmetic changed interger
+ IS_INT_MOD = 32, // arithmetic changed integer
IS_TRANSFORM = 64 // transformed integer
};
@@ -87,6 +88,13 @@ static u32 hshape;
static u64 screen_update;
static u64 last_update;
+#ifdef USE_HASHMAP
+// hashmap functions
+void hashmap_reset();
+bool hashmap_search_and_add(uint8_t type, uint64_t key);
+bool hashmap_search_and_add_ptr(uint8_t type, u8 *key);
+#endif
+
static struct range *add_range(struct range *ranges, u32 start, u32 end) {
struct range *r = ck_alloc_nozero(sizeof(struct range));
@@ -129,7 +137,6 @@ static struct range *pop_biggest_range(struct range **ranges) {
}
#ifdef _DEBUG
-// static int logging = 0;
static void dump(char *txt, u8 *buf, u32 len) {
u32 i;
@@ -140,6 +147,7 @@ static void dump(char *txt, u8 *buf, u32 len) {
}
+/*
static void dump_file(char *path, char *name, u32 counter, u8 *buf, u32 len) {
char fn[4096];
@@ -155,6 +163,8 @@ static void dump_file(char *path, char *name, u32 counter, u8 *buf, u32 len) {
}
+*/
+
#endif
static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u64 *cksum) {
@@ -379,7 +389,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len,
}
- if (++afl->stage_cur % screen_update == 0) { show_stats(afl); };
+ if (unlikely(++afl->stage_cur % screen_update == 0)) { show_stats(afl); };
}
@@ -571,7 +581,6 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) {
}
-//#ifdef CMPLOG_SOLVE_TRANSFORM
static int strntoll(const char *str, size_t sz, char **end, int base,
long long *out) {
@@ -656,7 +665,6 @@ static int is_hex(const char *str) {
}
-#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
// tests 4 bytes at location
static int is_base64(const char *str) {
@@ -732,12 +740,14 @@ static u32 from_base64(u8 *src, u8 *dst, u32 dst_len) {
}
-static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
+static u32 to_base64(u8 *src, u8 *dst, u32 dst_len) {
u32 i, j, v;
- u32 len = (dst_len >> 2) * 3;
+ // u32 len = (dst_len >> 2) * 3;
+ u32 len = (dst_len / 3) * 4;
+ if (dst_len % 3) len += 4;
- for (i = 0, j = 0; i < len; i += 3, j += 4) {
+ for (i = 0, j = 0; j < len; i += 3, j += 4) {
v = src[i];
v = i + 1 < len ? v << 8 | src[i + 1] : v << 8;
@@ -745,7 +755,8 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
dst[j] = base64_encode_table[(v >> 18) & 0x3F];
dst[j + 1] = base64_encode_table[(v >> 12) & 0x3F];
- if (i + 1 < len) {
+
+ if (i + 1 < dst_len) {
dst[j + 2] = base64_encode_table[(v >> 6) & 0x3F];
@@ -755,7 +766,7 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
}
- if (i + 2 < len) {
+ if (i + 2 < dst_len) {
dst[j + 3] = base64_encode_table[v & 0x3F];
@@ -767,12 +778,18 @@ static void to_base64(u8 *src, u8 *dst, u32 dst_len) {
}
+ dst[len] = 0;
+ return len;
+
}
+#ifdef WORD_SIZE_64
+static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
+ u128 pattern, u128 repl, u128 o_pattern,
+ u128 changed_val, u8 attr, u32 idx,
+ u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
+ u32 len, u8 do_reverse, u8 lvl, u8 *status);
#endif
-
-//#endif
-
static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 pattern, u64 repl, u64 o_pattern,
u64 changed_val, u8 attr, u32 idx, u32 taint_len,
@@ -786,53 +803,89 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 *o_buf_64 = (u64 *)&orig_buf[idx];
u32 *o_buf_32 = (u32 *)&orig_buf[idx];
u16 *o_buf_16 = (u16 *)&orig_buf[idx];
- u8 *o_buf_8 = &orig_buf[idx];
+ // u8 *o_buf_8 = &orig_buf[idx];
u32 its_len = MIN(len - idx, taint_len);
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
}
- // fprintf(stderr,
- // "Encode: %llx->%llx into %llx(<-%llx) at idx=%u "
- // "taint_len=%u shape=%u attr=%u\n",
- // o_pattern, pattern, repl, changed_val, idx, taint_len,
- // hshape, attr);
+ /*
+ fprintf(stderr,
+ "Encode: %llx->%llx into %llx(<-%llx) at idx=%u "
+ "taint_len=%u shape=%u attr=%u\n",
+ o_pattern, pattern, repl, changed_val, idx, taint_len,
+ hshape, attr);
+ */
+
+ u8 bytes;
+
+ switch (hshape) {
- //#ifdef CMPLOG_SOLVE_TRANSFORM
- // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
+ case 0:
+ case 1:
+ bytes = 1;
+ break;
+ case 2:
+ bytes = 2;
+ break;
+ case 3:
+ case 4:
+ bytes = 4;
+ break;
+ default:
+ bytes = 8;
+
+ }
+
+ // necessary for preventing heap access overflow
+ bytes = MIN(bytes, len - idx);
+ if (unlikely(bytes <= 1)) { return 0; }
+
+ // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
u8 *endptr;
u8 use_num = 0, use_unum = 0;
- unsigned long long unum;
- long long num;
+ unsigned long long unum = 0;
+ long long num = 0;
+
+ // if (afl->queue_cur->is_ascii) {
- if (afl->queue_cur->is_ascii) {
+ // we first check if our input are ascii numbers that are transformed to
+ // an integer and used for comparison:
- endptr = buf_8;
- if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) {
+ endptr = buf_8;
+ if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) {
- if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum))
- use_unum = 1;
+ if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) {
- } else
+ use_unum = 1;
- use_num = 1;
+ }
+
+ } else {
+
+ use_num = 1;
}
+ //}
+
#ifdef _DEBUG
if (idx == 0)
- fprintf(stderr, "ASCII is=%u use_num=%u use_unum=%u idx=%u %llx==%llx\n",
- afl->queue_cur->is_ascii, use_num, use_unum, idx, num, pattern);
+ fprintf(stderr,
+ "ASCII is=%u use_num=%u>%lld use_unum=%u>%llu idx=%u "
+ "pattern=0x%llx\n",
+ afl->queue_cur->is_ascii, use_num, num, use_unum, unum, idx,
+ pattern);
#endif
- // num is likely not pattern as atoi("AAA") will be zero...
+ // atoi("AAA") == 0 so !num means we have to investigate
if (use_num && ((u64)num == pattern || !num)) {
u8 tmp_buf[32];
@@ -881,29 +934,6 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
if (pattern != o_pattern && repl == changed_val && attr <= IS_EQUAL) {
u64 b_val, o_b_val, mask;
- u8 bytes;
-
- switch (hshape) {
-
- case 0:
- case 1:
- bytes = 1;
- break;
- case 2:
- bytes = 2;
- break;
- case 3:
- case 4:
- bytes = 4;
- break;
- default:
- bytes = 8;
-
- }
-
- // necessary for preventing heap access overflow
- bytes = MIN(bytes, len - idx);
-
switch (bytes) {
case 0: // cannot happen
@@ -961,10 +991,12 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..."
s64 diff = pattern - b_val;
s64 o_diff = o_pattern - o_b_val;
- /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
- hshape, o_pattern, o_b_val, o_diff);
- fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
- b_val, diff); */
+ /*
+ fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx,
+ hshape, o_pattern, o_b_val, o_diff);
+ fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern,
+ b_val, diff);
+ */
if (diff == o_diff && diff) {
// this could be an arithmetic transformation
@@ -1120,7 +1152,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
- //#endif
+ // #endif
// we only allow this for ascii2integer (above) so leave if this is the case
if (unlikely(pattern == o_pattern)) { return 0; }
@@ -1243,6 +1275,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
+ /*
if (*status != 1) { // u8
// if (its_len >= 1)
@@ -1267,15 +1300,145 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
+ */
+
}
- // here we add and subract 1 from the value, but only if it is not an
+ // If 'S' is set for cmplog mode then we try a scale encoding of the value.
+ // Currently we can only handle bytes up to 1 << 55 on 32 bit and 1 << 119
+ // on 64 bit systems.
+ // Caveat: This implementation here works only on little endian systems.
+
+ if (attr < IS_FP && (afl->cmplog_enable_scale || lvl >= LVL3) &&
+ repl == changed_val) {
+
+ u8 do_call = 1;
+ u64 new_val = repl << 2;
+ u32 ilen = 0;
+
+ if (changed_val <= 255) {
+
+ ilen = 1;
+
+ } else if (new_val <= 65535) {
+
+ new_val += 1; // two byte mode
+ ilen = 2;
+
+ } else if (new_val <= 4294967295) {
+
+ new_val += 2; // four byte mode
+ ilen = 4;
+
+ } else {
+
+#ifndef WORD_SIZE_64
+ if (repl <= 0x00ffffffffffffff) {
+
+ new_val = repl << 8;
+ u8 scale_len = 0;
+ u64 tmp_val = repl;
+ while (tmp_val) {
+
+ tmp_val >>= 8;
+ ++scale_len;
+
+ } // scale_len will be >= 4;
+
+ if (scale_len >= 4) {
+
+ scale_len -= 4;
+
+ } else {
+
+ scale_len = 0;
+
+ };
+
+ new_val += (scale_len << 2) + 3;
+ ilen = scale_len + 5;
+
+ } else {
+
+ do_call = 0;
+
+ }
+
+#else
+ {
+
+ u128 new_vall = ((u128)repl) << 8;
+ u8 scale_len = 0;
+ u128 tmp_val = (u128)repl;
+
+ while (tmp_val) {
+
+ tmp_val >>= 8;
+ ++scale_len;
+
+ } // scale_len will be >= 4;
+
+ if (scale_len >= 4) {
+
+ scale_len -= 4;
+
+ } else {
+
+ scale_len = 0;
+
+ };
+
+ new_vall += (scale_len << 2) + 3;
+ ilen = scale_len + 5;
+
+ if (ilen <= its_len && ilen > 1) {
+
+ u8 tmpbuf[32];
+ memcpy(tmpbuf, buf + idx, ilen);
+ memcpy(buf + idx, (char *)&new_vall, ilen);
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ #ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, (char *)&new_vall, ilen); }
+ #endif
+ memcpy(buf + idx, tmpbuf, ilen);
+
+ };
+
+ do_call = 0;
+
+ }
+
+#endif
+
+ }
+
+ if (do_call) {
+
+ if (ilen <= its_len && ilen > 1) {
+
+ u8 tmpbuf[32];
+ memcpy(tmpbuf, buf + idx, ilen);
+ memcpy(buf + idx, (char *)&new_val, ilen);
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+#ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, (char *)&new_val, ilen); }
+#endif
+ memcpy(buf + idx, tmpbuf, ilen);
+
+ };
+
+ }
+
+ }
+
+ // here we add and subtract 1 from the value, but only if it is not an
// == or != comparison
// Bits: 1 = Equal, 2 = Greater, 4 = Lesser, 8 = Float
// 16 = modified float, 32 = modified integer (modified = wont match
// in original buffer)
- //#ifdef CMPLOG_SOLVE_ARITHMETIC
if (!afl->cmplog_enable_arith || lvl < LVL3 || attr == IS_TRANSFORM) {
return 0;
@@ -1440,8 +1603,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
- //#endif /*
- // CMPLOG_SOLVE_ARITHMETIC
+ // #endif /*
+ // CMPLOG_SOLVE_ARITHMETIC
return 0;
@@ -1455,7 +1618,7 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
u32 taint_len, u8 *orig_buf, u8 *buf, u8 *cbuf,
u32 len, u8 do_reverse, u8 lvl, u8 *status) {
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@@ -1536,6 +1699,77 @@ static u8 cmp_extend_encodingN(afl_state_t *afl, struct cmp_header *h,
}
+ // Scale encoding only works on little endian systems
+
+ if (attr < IS_FP && attr < 32 &&
+ (afl->cmplog_enable_scale || lvl >= LVL3)) {
+
+ u128 new_val = repl << 2;
+ u128 max_scale = (u128)1 << 120;
+ u32 ilen = 0;
+ u8 do_call = 1;
+
+ if (new_val <= 255) {
+
+ ilen = 1;
+
+ } else if (new_val <= 65535) {
+
+ new_val += 1; // two byte mode
+ ilen = 2;
+
+ } else if (new_val <= 4294967295) {
+
+ new_val += 2; // four byte mode
+ ilen = 4;
+
+ } else if (repl < max_scale) {
+
+ new_val = (u128)repl << 8;
+ u8 scale_len = 0;
+ u128 tmp_val = (u128)repl;
+ while (tmp_val) {
+
+ tmp_val >>= 8;
+ ++scale_len;
+
+ } // scale_len will be >= 4;
+
+ if (scale_len >= 4) {
+
+ scale_len -= 4;
+
+ } else {
+
+ scale_len = 0;
+
+ };
+
+ new_val += (scale_len << 2) + 3;
+ ilen = scale_len + 5;
+
+ } else {
+
+ do_call = 0;
+
+ }
+
+ if (do_call && ilen <= its_len) {
+
+ u8 tmpbuf[32];
+ memcpy(tmpbuf, buf + idx, ilen);
+ memcpy(buf + idx, (char *)&new_val, ilen);
+
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ #ifdef CMPLOG_COMBINE
+ if (*status == 1) { memcpy(cbuf + idx, (char *)&new_val, ilen); }
+ #endif
+ memcpy(buf + idx, tmpbuf, ilen);
+
+ };
+
+ }
+
}
return 0;
@@ -1606,7 +1840,7 @@ static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) {
for (k = 0; k < size; ++k) {
#else
- u32 off = 16 - size;
+ u32 off = 16 - size;
for (k = 16 - size; k < 16; ++k) {
#endif
@@ -1659,6 +1893,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
hshape = SHAPE_BYTES(h->shape);
+ if (hshape < 2) { return 0; }
+
if (h->hits > CMP_MAP_H) {
loggeds = CMP_MAP_H;
@@ -1721,6 +1957,19 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
+#ifdef USE_HASHMAP
+ // TODO: add attribute? not sure
+ if (hshape <= 8 && hashmap_search_and_add(hshape - 1, o->v0) &&
+ hashmap_search_and_add(hshape - 1, orig_o->v0) &&
+ hashmap_search_and_add(hshape - 1, o->v1) &&
+ hashmap_search_and_add(hshape - 1, orig_o->v1)) {
+
+ continue;
+
+ }
+
+#endif
+
#ifdef _DEBUG
fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n",
orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape);
@@ -1948,11 +2197,11 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
#ifndef CMPLOG_COMBINE
(void)(cbuf);
#endif
- //#ifndef CMPLOG_SOLVE_TRANSFORM
- // (void)(changed_val);
- //#endif
+ // #ifndef CMPLOG_SOLVE_TRANSFORM
+ // (void)(changed_val);
+ // #endif
- if (afl->fsrv.total_execs - last_update > screen_update) {
+ if (unlikely(afl->fsrv.total_execs - last_update > screen_update)) {
show_stats(afl);
last_update = afl->fsrv.total_execs;
@@ -1988,29 +2237,35 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
if (l0 >= 0x80 || ol0 >= 0x80) {
- l0 -= 0x80;
- l1 -= 0x80;
- ol0 -= 0x80;
- ol1 -= 0x80;
+ if (l0 >= 0x80) { l0 -= 0x80; }
+ if (l1 >= 0x80) { l1 -= 0x80; }
+ if (ol0 >= 0x80) { ol0 -= 0x80; }
+ if (ol1 >= 0x80) { ol1 -= 0x80; }
}
- if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 ||
- ol0 > 31 || ol1 > 31) {
+ if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 32 || l1 > 32 ||
+ ol0 > 32 || ol1 > 32) {
l0 = ol0 = hshape;
}
u8 lmax = MAX(l0, ol0);
- u8 save[40];
+ u8 save[80];
u32 saved_idx = idx, pre, from = 0, to = 0, i, j;
u32 its_len = MIN(MIN(lmax, hshape), len - idx);
its_len = MIN(its_len, taint_len);
u32 saved_its_len = its_len;
+ // fprintf(stderr, "its_len=%u repl=%s\n", its_len, repl);
+
+ if (its_len <= 1) { return 0; }
+
if (lvl & LVL3) {
+ if (memcmp(changed_val, repl, its_len) != 0) { return 0; }
+
u32 max_to = MIN(4U, idx);
if (!(lvl & LVL1) && max_to) { from = 1; }
to = max_to;
@@ -2021,27 +2276,32 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
(void)(j);
#ifdef _DEBUG
- fprintf(stderr, "RTN T idx=%u lvl=%02x is_txt=%u shape=%u/%u ", idx, lvl,
- o->v0_len >= 0x80 ? 1 : 0, hshape, l0);
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", orig_buf[idx + j]);
- fprintf(stderr, " -> ");
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", o_pattern[j]);
- fprintf(stderr, " <= ");
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", repl[j]);
- fprintf(stderr, "\n");
- fprintf(stderr, " ");
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", buf[idx + j]);
- fprintf(stderr, " -> ");
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", pattern[j]);
- fprintf(stderr, " <= ");
- for (j = 0; j < 8; j++)
- fprintf(stderr, "%02x", changed_val[j]);
- fprintf(stderr, "\n");
+ if (idx == 0) {
+
+ fprintf(stderr, "RTN T idx=%u lvl=%02x is_txt=%u shape=%u/%u ", idx, lvl,
+ o->v0_len >= 0x80 ? 1 : 0, hshape, l0);
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", orig_buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", o_pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", repl[j]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", buf[idx + j]);
+ fprintf(stderr, " -> ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", pattern[j]);
+ fprintf(stderr, " <= ");
+ for (j = 0; j < 8; j++)
+ fprintf(stderr, "%02x", changed_val[j]);
+ fprintf(stderr, "\n");
+
+ }
+
#endif
// Try to match the replace value up to 4 bytes before the current idx.
@@ -2050,6 +2310,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
// if (memcmp(user_val, "TEST-VALUE") == 0) ...
// We only do this in lvl 3, otherwise we only do direct matching
+ // fprintf(stderr, "XXXX FROMB64 saved_idx=%u its_len=%u from=%u to=%u FROMHEX
+ // repl=%s\n", saved_idx, saved_its_len, from, to, repl);
+
for (pre = from; pre <= to; pre++) {
if (*status != 1 && (!pre || !memcmp(buf + saved_idx - pre, repl, pre))) {
@@ -2059,7 +2322,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
for (i = 0; i < its_len; ++i) {
- if ((pattern[i] != buf[idx + i] && o_pattern[i] != orig_buf[idx + i]) ||
+ if ((pattern[i] != buf[idx + i] || o_pattern[i] != orig_buf[idx + i]) ||
*status == 1) {
break;
@@ -2089,12 +2352,10 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
if (afl->cmplog_enable_transform && (lvl & LVL3)) {
u32 toupper = 0, tolower = 0, xor = 0, arith = 0, tohex = 0, fromhex = 0;
-#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
u32 tob64 = 0, fromb64 = 0;
-#endif
u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0;
u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0;
- u8 xor_val[32], arith_val[32], tmp[48];
+ u8 xor_val[64], arith_val[64], tmp[64];
idx = saved_idx;
its_len = saved_its_len;
@@ -2144,7 +2405,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- if (i < 16 && is_hex(repl + (i << 1))) {
+ if (afl->cmplog_enable_xtreme_transform && i < 16 &&
+ is_hex(repl + (i << 1))) {
++tohex;
@@ -2163,9 +2425,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- if ((i % 2)) {
+ if (afl->cmplog_enable_xtreme_transform && (i % 2) == 1) {
- if (len > idx + i + 1 && is_hex(orig_buf + idx + i)) {
+ if (len > idx + i + 1 && is_hex(orig_buf + idx + i - 1)) {
fromhex += 2;
@@ -2187,20 +2449,23 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
-#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
- if (i % 3 == 2 && i < 24) {
+ if (afl->cmplog_enable_xtreme_transform) {
- if (is_base64(repl + ((i / 3) << 2))) tob64 += 3;
+ if (i % 3 == 2 && i < 24) {
- }
+ if (is_base64(repl + ((i / 3) << 2))) tob64 += 3;
- if (i % 4 == 3 && i < 24) {
+ }
- if (is_base64(orig_buf + idx + i - 3)) fromb64 += 4;
+ // fprintf(stderr, "X FROMB64 idx=%u i=%u repl=%s\n", saved_idx, i,
+ // repl);
+ if (i % 4 == 3 && i < 24) {
- }
+ if (is_base64(orig_buf + idx + i - 3)) fromb64 += 4;
-#endif
+ }
+
+ }
if ((o_pattern[i] ^ orig_buf[idx + i]) == xor_val[i] && xor_val[i]) {
@@ -2229,45 +2494,70 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
#ifdef _DEBUG
- fprintf(stderr,
- "RTN idx=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u "
- "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u "
- "from_0=%u from_slash=%u from_x=%u\n",
- idx, i, xor, arith, tolower, toupper, tohex, fromhex, to_0,
- to_slash, to_x, from_0, from_slash, from_x);
- #ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
- fprintf(stderr, "RTN idx=%u loop=%u tob64=%u from64=%u\n", tob64,
- fromb64);
- #endif
+ if (idx == 0) {
+
+ fprintf(stderr, "RTN Z %s %s %s %s repl=%s\n", buf, pattern, orig_buf,
+ o_pattern, repl);
+ fprintf(
+ stderr,
+ "RTN Z idx=%u len=%u loop=%u xor=%u arith=%u tolower=%u toupper=%u "
+ "tohex=%u fromhex=%u to_0=%u to_slash=%u to_x=%u "
+ "from_0=%u from_slash=%u from_x=%u\n",
+ idx, its_len, i, xor, arith, tolower, toupper, tohex, fromhex, to_0,
+ to_slash, to_x, from_0, from_slash, from_x);
+ if (afl->cmplog_enable_xtreme_transform) {
+
+ fprintf(stderr, "RTN Z idx=%u loop=%u tob64=%u from64=%u\n", idx, i,
+ tob64, fromb64);
+
+ }
+
+ }
+
#endif
-#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
- // input is base64 and converted to binary? convert repl to base64!
- if ((i % 4) == 3 && i < 24 && fromb64 > i) {
+ if (afl->cmplog_enable_xtreme_transform) {
- to_base64(repl, tmp, i + 1);
- memcpy(buf + idx, tmp, i + 1);
- if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
- // fprintf(stderr, "RTN ATTEMPT fromb64 %u result %u\n", fromb64,
- // *status);
+ // input is base64 and converted to binary? convert repl to base64!
+ // fprintf(stderr, "FROMB64 idx=%u i=%u %% 4 == 3 && i < 24 &&
+ // fromb64=%u > i, repl=%s\n", saved_idx, i, fromb64, repl);
+ if ((i % 4) == 3 && i < 24 && fromb64 > i) {
- }
+ for (u32 hlen = i; hlen + saved_idx < len && hlen <= its_len;
+ ++hlen) {
- // input is converted to base64? decode repl with base64!
- if ((i % 3) == 2 && i < 24 && tob64 > i) {
+ u32 res = to_base64(repl, tmp, hlen);
+ // fprintf(stderr, "FROMB64 GOGO! idx=%u repl=%s tmp[%u]=%s
+ // hlen=%u\n", saved_idx, repl, res, tmp, hlen);
+ if (res + saved_idx < len) {
- u32 olen = from_base64(repl, tmp, i + 1);
- memcpy(buf + idx, tmp, olen);
- if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
- // fprintf(stderr, "RTN ATTEMPT tob64 %u idx=%u result %u\n", tob64,
- // idx, *status);
+ memcpy(buf + idx, tmp, res);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT FROMB64 idx=%u fromb64 %u %s %s
+ // result %u\n", saved_idx, fromb64, tmp, repl,
+ // *status);
- }
+ }
-#endif
+ }
+
+ }
+
+ // input is converted to base64? decode repl with base64!
+ if ((i % 3) == 2 && i < 24 && tob64 > i) {
+
+ u32 olen = from_base64(repl, tmp, i + 1);
+ memcpy(buf + idx, tmp, olen);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ // fprintf(stderr, "RTN ATTEMPT tob64 %u idx=%u result %u\n", tob64,
+ // idx, *status);
+
+ }
+
+ }
// input is converted to hex? convert repl to binary!
- if (i < 16 && tohex > i) {
+ if (afl->cmplog_enable_xtreme_transform && i < 16 && tohex > i) {
u32 off;
if (to_slash + to_x + to_0 == 2) {
@@ -2292,8 +2582,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
// input is hex and converted to binary? convert repl to hex!
- if (i && (i % 2) && i < 16 && fromhex &&
- fromhex + from_slash + from_x + from_0 > i) {
+ if (afl->cmplog_enable_xtreme_transform && (i % 2) == 1 && i < 16 &&
+ fromhex && fromhex + from_slash + from_x + from_0 > i) {
u8 off = 0;
if (from_slash && from_x) {
@@ -2328,31 +2618,37 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- if (to_up == 1) {
+ for (u32 hlen = i; hlen <= (i << 1) && hlen + idx < len; hlen += i) {
- for (j = 0; j <= (i >> 1); j++) {
+ if (to_up == 1) {
- tmp[off + (j << 1)] = hex_table_up[repl[j] >> 4];
- tmp[off + (j << 1) + 1] = hex_table_up[repl[j] % 16];
+ for (j = 0; j <= (hlen >> 1); j++) {
- }
+ tmp[off + (j << 1)] = hex_table_up[repl[j] >> 4];
+ tmp[off + (j << 1) + 1] = hex_table_up[repl[j] % 16];
- } else {
+ }
+
+ } else {
- for (j = 0; j <= (i >> 1); j++) {
+ for (j = 0; j <= (hlen >> 1); j++) {
- tmp[off + (j << 1)] = hex_table_low[repl[j] >> 4];
- tmp[off + (j << 1) + 1] = hex_table_low[repl[j] % 16];
+ tmp[off + (j << 1)] = hex_table_low[repl[j] >> 4];
+ tmp[off + (j << 1) + 1] = hex_table_low[repl[j] % 16];
+
+ }
}
- }
+ u32 tmp_l = hlen + 1 + off;
+ memcpy(buf + idx, tmp, tmp_l);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ tmp[tmp_l] = 0;
+ // fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result
+ // %u\n", idx, len, fromhex, tmp, repl, *status);
+ memcpy(buf + idx, save, tmp_l);
- memcpy(buf + idx, tmp, i + 1 + off);
- if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
- // fprintf(stderr, "RTN ATTEMPT fromhex %u result %u\n", fromhex,
- // *status);
- memcpy(buf + idx, save, i + 1 + off);
+ }
}
@@ -2401,11 +2697,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
if ((i >= 7 &&
(i >= xor&&i >= arith &&i >= tolower &&i >= toupper &&i > tohex &&i >
- (fromhex + from_0 + from_x + from_slash + 1)
-#ifdef CMPLOG_SOLVE_TRANSFORM_BASE64
- && i > tob64 + 3 && i > fromb64 + 4
-#endif
- )) ||
+ (fromhex + from_0 + from_x + from_slash + 1) &&
+ (afl->cmplog_enable_xtreme_transform && i > tob64 + 3 &&
+ i > fromb64 + 4))) ||
repl[i] != changed_val[i] || *status == 1) {
break;
@@ -2418,8 +2712,6 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- //#endif
-
return 0;
}
@@ -2429,11 +2721,13 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
struct tainted *t;
struct cmp_header *h = &afl->shm.cmp_map->headers[key];
- u32 i, j, idx, have_taint = 1, taint_len, loggeds;
+ u32 i, idx, have_taint = 1, taint_len, loggeds;
u8 status = 0, found_one = 0;
hshape = SHAPE_BYTES(h->shape);
+ if (hshape < 2) { return 0; }
+
if (h->hits > CMP_MAP_RTN_H) {
loggeds = CMP_MAP_RTN_H;
@@ -2452,36 +2746,52 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
struct cmpfn_operands *orig_o =
&((struct cmpfn_operands *)afl->orig_cmp_map->log[key])[i];
- // opt not in the paper
- for (j = 0; j < i; ++j) {
+ /*
+ // opt not in the paper
+ for (j = 0; j < i; ++j) {
- if (!memcmp(&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[j], o,
- sizeof(struct cmpfn_operands))) {
+ if (!memcmp(&((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[j],
+ o, sizeof(struct cmpfn_operands))) {
- goto rtn_fuzz_next_iter;
+ goto rtn_fuzz_next_iter;
- }
+ }
- }
+ }
- /*
+ */
+
+#ifdef _DEBUG
+ u32 j;
struct cmp_header *hh = &afl->orig_cmp_map->headers[key];
- fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id,
- hshape, h->attribute);
+ fprintf(stderr, "RTN N hits=%u shape=%u attr=%u v0=", h->hits, hshape,
+ h->attribute);
for (j = 0; j < 8; j++)
fprintf(stderr, "%02x", o->v0[j]);
fprintf(stderr, " v1=");
for (j = 0; j < 8; j++)
fprintf(stderr, "%02x", o->v1[j]);
- fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=", hh->hits,
- hh->id, hshape, hh->attribute);
+ fprintf(stderr, "\nRTN O hits=%u shape=%u attr=%u o0=", hh->hits, hshape,
+ hh->attribute);
for (j = 0; j < 8; j++)
fprintf(stderr, "%02x", orig_o->v0[j]);
fprintf(stderr, " o1=");
for (j = 0; j < 8; j++)
fprintf(stderr, "%02x", orig_o->v1[j]);
fprintf(stderr, "\n");
- */
+#endif
+
+#ifdef USE_HASHMAP
+ if (hshape <= 8 && hashmap_search_and_add_ptr(hshape - 1, o->v0) &&
+ hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) &&
+ hashmap_search_and_add_ptr(hshape - 1, o->v1) &&
+ hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) {
+
+ continue;
+
+ }
+
+#endif
t = taint;
while (t->next) {
@@ -2515,7 +2825,7 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
status = 0;
#ifdef _DEBUG
- int w;
+ u32 w;
fprintf(stderr, "key=%u idx=%u len=%u o0=", key, idx, hshape);
for (w = 0; w < hshape; ++w)
fprintf(stderr, "%02x", orig_o->v0[w]);
@@ -2592,6 +2902,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
// shape_len), check_if_text_buf((u8 *)&o->v1, shape_len), v0_len,
// o->v0, v1_len, o->v1);
+ // Note that this check differs from the line 1901, for RTN we are more
+ // opportunistic for adding to the dictionary than cmps
if (!memcmp(o->v0, orig_o->v0, v0_len) ||
(!found_one || check_if_text_buf((u8 *)&o->v0, v0_len) == v0_len))
maybe_add_auto(afl, o->v0, v0_len);
@@ -2603,7 +2915,7 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
}
- rtn_fuzz_next_iter:
+ // rtn_fuzz_next_iter:
afl->stage_cur++;
}
@@ -2747,6 +3059,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
// Start insertion loop
+#ifdef USE_HASHMAP
+ hashmap_reset();
+#endif
+
u64 orig_hit_cnt, new_hit_cnt;
u64 orig_execs = afl->fsrv.total_execs;
orig_hit_cnt = afl->queued_items + afl->saved_crashes;
@@ -2816,12 +3132,7 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
}
- } else if ((lvl & LVL1)
-
- //#ifdef CMPLOG_SOLVE_TRANSFORM
- || ((lvl & LVL3) && afl->cmplog_enable_transform)
- //#endif
- ) {
+ } else if ((lvl & LVL1) || ((lvl & LVL3) && afl->cmplog_enable_transform)) {
if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, cbuf, len, lvl, taint))) {
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index ac4fb4a9..b62db1ea 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -5,12 +5,12 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com> and
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -60,6 +60,23 @@ fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) {
fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon);
+ /* If post_run() function is defined in custom mutator, the function will be
+ called each time after AFL++ executes the target program. */
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (unlikely(el->afl_custom_post_run)) {
+
+ el->afl_custom_post_run(el->data);
+
+ }
+
+ });
+
+ }
+
#ifdef PROFILING
clock_gettime(CLOCK_REALTIME, &spec);
time_spent_start = (spec.tv_sec * 1000000000) + spec.tv_nsec;
@@ -152,20 +169,16 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- if (unlikely(afl->custom_mutators_count)) {
-
- LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
-
- if (el->afl_custom_fuzz_send) {
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
- el->afl_custom_fuzz_send(el->data, *mem, new_size);
- sent = 1;
+ if (el->afl_custom_fuzz_send) {
- }
+ el->afl_custom_fuzz_send(el->data, *mem, new_size);
+ sent = 1;
- });
+ }
- }
+ });
if (likely(!sent)) {
@@ -186,7 +199,7 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- } else {
+ } else { /* !afl->custom_mutators_count */
if (unlikely(len < afl->min_length && !fix)) {
@@ -198,27 +211,8 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- if (unlikely(afl->custom_mutators_count)) {
-
- LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
-
- if (el->afl_custom_fuzz_send) {
-
- el->afl_custom_fuzz_send(el->data, *mem, len);
- sent = 1;
-
- }
-
- });
-
- }
-
- if (likely(!sent)) {
-
- /* boring uncustom. */
- afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
-
- }
+ /* boring uncustom. */
+ afl_fsrv_write_to_testcase(&afl->fsrv, *mem, len);
}
@@ -415,6 +409,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
u32 use_tmout = afl->fsrv.exec_tmout;
u8 *old_sn = afl->stage_name;
+ u64 calibration_start_us = get_cur_time_us();
if (unlikely(afl->shm.cmplog_mode)) { q->exec_cksum = 0; }
/* Be a bit more generous about timeouts when resuming sessions, or when
@@ -510,6 +505,10 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
fault = fuzz_run_target(afl, &afl->fsrv, use_tmout);
+ // update the time spend in calibration after each execution, as those may
+ // be slow
+ update_calibration_time(afl, &calibration_start_us);
+
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
we want to bail out quickly. */
@@ -607,6 +606,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
q->exec_us = diff_us / afl->stage_max;
+ if (unlikely(!q->exec_us)) { q->exec_us = 1; }
+
q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits);
q->handicap = handicap;
q->cal_failed = 0;
@@ -656,6 +657,7 @@ abort_calibration:
if (!first_run) { show_stats(afl); }
+ update_calibration_time(afl, &calibration_start_us);
return fault;
}
@@ -675,11 +677,16 @@ void sync_fuzzers(afl_state_t *afl) {
afl->stage_max = afl->stage_cur = 0;
afl->cur_depth = 0;
+ u64 sync_start_us = get_cur_time_us();
/* Look at the entries created for every other fuzzer in the sync directory.
*/
while ((sd_ent = readdir(sd))) {
+ // since sync can take substantial amounts of time, update time spend every
+ // iteration
+ update_sync_time(afl, &sync_start_us);
+
u8 qd_synced_path[PATH_MAX], qd_path[PATH_MAX];
u32 min_accept = 0, next_min_accept = 0;
@@ -766,6 +773,8 @@ void sync_fuzzers(afl_state_t *afl) {
afl->stage_cur = 0;
afl->stage_max = 0;
+ show_stats(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. */
@@ -817,15 +826,15 @@ void sync_fuzzers(afl_state_t *afl) {
/* See what happens. We rely on save_if_interesting() to catch major
errors and save the test case. */
- (void)write_to_testcase(afl, (void **)&mem, st.st_size, 1);
+ u32 new_len = write_to_testcase(afl, (void **)&mem, st.st_size, 1);
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
if (afl->stop_soon) { goto close_sync; }
afl->syncing_party = sd_ent->d_name;
- afl->queued_imported +=
- save_if_interesting(afl, mem, st.st_size, fault);
+ afl->queued_imported += save_if_interesting(afl, mem, new_len, fault);
+ show_stats(afl);
afl->syncing_party = 0;
munmap(mem, st.st_size);
@@ -867,6 +876,9 @@ void sync_fuzzers(afl_state_t *afl) {
if (afl->foreign_sync_cnt) read_foreign_testcases(afl, 0);
+ // add time in sync one last time
+ update_sync_time(afl, &sync_start_us);
+
afl->last_sync_time = get_cur_time();
afl->last_sync_cycle = afl->queue_cycle;
@@ -878,8 +890,9 @@ void sync_fuzzers(afl_state_t *afl) {
u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
+ u8 needs_write = 0, fault = 0;
u32 orig_len = q->len;
-
+ u64 trim_start_us = get_cur_time_us();
/* Custom mutator trimmer */
if (afl->custom_mutators_count) {
@@ -903,11 +916,15 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
}
- if (custom_trimmed) return trimmed_case;
+ if (custom_trimmed) {
+
+ fault = trimmed_case;
+ goto abort_trimming;
+
+ }
}
- u8 needs_write = 0, fault = 0;
u32 trim_exec = 0;
u32 remove_len;
u32 len_p2;
@@ -918,7 +935,12 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
detected, it will still work to some extent, so we don't check for
this. */
- if (q->len < 5) { return 0; }
+ if (unlikely(q->len < 5)) {
+
+ fault = 0;
+ goto abort_trimming;
+
+ }
afl->stage_name = afl->stage_name_buf;
afl->bytes_trim_in += q->len;
@@ -952,6 +974,8 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
+ update_trim_time(afl, &trim_start_us);
+
if (afl->stop_soon || fault == FSRV_RUN_ERROR) { goto abort_trimming; }
/* Note that we don't keep track of crashes or hangs here; maybe TODO?
@@ -978,7 +1002,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
/* Let's save a clean trace, which will be needed by
update_bitmap_score once we're done with the trimming stuff. */
-
if (!needs_write) {
needs_write = 1;
@@ -993,7 +1016,6 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
}
/* Since this can be slow, update the screen every now and then. */
-
if (!(trim_exec++ % afl->stats_update_freq)) { show_stats(afl); }
++afl->stage_cur;
@@ -1008,6 +1030,68 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
if (needs_write) {
+ // run afl_custom_post_process
+
+ if (unlikely(afl->custom_mutators_count) &&
+ likely(!afl->afl_env.afl_post_process_keep_original)) {
+
+ ssize_t new_size = q->len;
+ u8 *new_mem = in_buf;
+ u8 *new_buf = NULL;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ new_size = el->afl_custom_post_process(el->data, new_mem, new_size,
+ &new_buf);
+
+ if (unlikely(!new_buf || new_size <= 0)) {
+
+ new_size = 0;
+ new_buf = new_mem;
+
+ } else {
+
+ new_mem = new_buf;
+
+ }
+
+ }
+
+ });
+
+ if (unlikely(!new_size)) {
+
+ new_size = q->len;
+ new_mem = in_buf;
+
+ }
+
+ if (unlikely(new_size < afl->min_length)) {
+
+ new_size = afl->min_length;
+
+ } else if (unlikely(new_size > afl->max_length)) {
+
+ new_size = afl->max_length;
+
+ }
+
+ q->len = new_size;
+
+ if (new_mem != in_buf && new_mem != NULL) {
+
+ new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+ memcpy(new_buf, new_mem, new_size);
+
+ in_buf = new_buf;
+
+ }
+
+ }
+
s32 fd;
if (unlikely(afl->no_unlink)) {
@@ -1045,8 +1129,9 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) {
}
abort_trimming:
-
afl->bytes_trim_out += q->len;
+ update_trim_time(afl, &trim_start_us);
+
return fault;
}
@@ -1110,4 +1195,3 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
return 0;
}
-
diff --git a/src/afl-fuzz-skipdet.c b/src/afl-fuzz-skipdet.c
new file mode 100644
index 00000000..e52d59a3
--- /dev/null
+++ b/src/afl-fuzz-skipdet.c
@@ -0,0 +1,403 @@
+
+
+#include "afl-fuzz.h"
+
+void flip_range(u8 *input, u32 pos, u32 size) {
+
+ for (u32 i = 0; i < size; i++)
+ input[pos + i] ^= 0xFF;
+
+ return;
+
+}
+
+#define MAX_EFF_TIMEOUT (10 * 60 * 1000)
+#define MAX_DET_TIMEOUT (15 * 60 * 1000)
+u8 is_det_timeout(u64 cur_ms, u8 is_flip) {
+
+ if (is_flip) {
+
+ if (unlikely(get_cur_time() - cur_ms > MAX_EFF_TIMEOUT)) return 1;
+
+ } else {
+
+ if (unlikely(get_cur_time() - cur_ms > MAX_DET_TIMEOUT)) return 1;
+
+ }
+
+ return 0;
+
+}
+
+/* decide if the seed should be deterministically fuzzed */
+
+u8 should_det_fuzz(afl_state_t *afl, struct queue_entry *q) {
+
+ if (!afl->skipdet_g->virgin_det_bits) {
+
+ afl->skipdet_g->virgin_det_bits =
+ (u8 *)ck_alloc(sizeof(u8) * afl->fsrv.map_size);
+
+ }
+
+ if (!q->favored || q->passed_det) return 0;
+ if (!q->trace_mini) return 0;
+
+ if (!afl->skipdet_g->last_cov_undet)
+ afl->skipdet_g->last_cov_undet = get_cur_time();
+
+ if (get_cur_time() - afl->skipdet_g->last_cov_undet >= THRESHOLD_DEC_TIME) {
+
+ if (afl->skipdet_g->undet_bits_threshold >= 2) {
+
+ afl->skipdet_g->undet_bits_threshold *= 0.75;
+ afl->skipdet_g->last_cov_undet = get_cur_time();
+
+ }
+
+ }
+
+ u32 new_det_bits = 0;
+
+ for (u32 i = 0; i < afl->fsrv.map_size; i++) {
+
+ if (unlikely(q->trace_mini[i >> 3] & (1 << (i & 7)))) {
+
+ if (!afl->skipdet_g->virgin_det_bits[i]) { new_det_bits++; }
+
+ }
+
+ }
+
+ if (!afl->skipdet_g->undet_bits_threshold)
+ afl->skipdet_g->undet_bits_threshold = new_det_bits * 0.05;
+
+ if (new_det_bits >= afl->skipdet_g->undet_bits_threshold) {
+
+ afl->skipdet_g->last_cov_undet = get_cur_time();
+ q->skipdet_e->undet_bits = new_det_bits;
+
+ for (u32 i = 0; i < afl->fsrv.map_size; i++) {
+
+ if (unlikely(q->trace_mini[i >> 3] & (1 << (i & 7)))) {
+
+ if (!afl->skipdet_g->virgin_det_bits[i])
+ afl->skipdet_g->virgin_det_bits[i] = 1;
+
+ }
+
+ }
+
+ return 1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ consists of two stages that
+ return 0 if exec failed.
+*/
+
+u8 skip_deterministic_stage(afl_state_t *afl, u8 *orig_buf, u8 *out_buf,
+ u32 len, u64 before_det_time) {
+
+ u64 orig_hit_cnt, new_hit_cnt;
+
+ if (afl->queue_cur->skipdet_e->done_eff) return 1;
+
+ if (!should_det_fuzz(afl, afl->queue_cur)) return 1;
+
+ /* Add check to make sure that for seeds without too much undet bits,
+ we ignore them */
+
+ /******************
+ * SKIP INFERENCE *
+ ******************/
+
+ afl->stage_short = "inf";
+ afl->stage_name = "inference";
+ afl->stage_cur = 0;
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ u8 *inf_eff_map = (u8 *)ck_alloc(sizeof(u8) * len);
+ memset(inf_eff_map, 1, sizeof(u8) * len);
+
+ if (common_fuzz_stuff(afl, orig_buf, len)) { return 0; }
+
+ u64 prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ u64 _prev_cksum = prev_cksum;
+
+ if (MINIMAL_BLOCK_SIZE * 8 < len) {
+
+ // u64 size_skiped = 0, quick_skip_exec = total_execs, quick_skip_time =
+ // get_cur_time();
+ u64 pre_inf_exec = afl->fsrv.total_execs, pre_inf_time = get_cur_time();
+
+ /* if determine stage time / input size is too small, just go ahead */
+
+ u32 pos = 0, cur_block_size = MINIMAL_BLOCK_SIZE, max_block_size = len / 8;
+
+ while (pos < len - 1) {
+
+ cur_block_size = MINIMAL_BLOCK_SIZE;
+
+ while (cur_block_size < max_block_size) {
+
+ u32 flip_block_size =
+ (cur_block_size + pos < len) ? cur_block_size : len - 1 - pos;
+
+ afl->stage_cur += 1;
+
+ flip_range(out_buf, pos, flip_block_size);
+
+ if (common_fuzz_stuff(afl, out_buf, len)) return 0;
+
+ flip_range(out_buf, pos, flip_block_size);
+
+ u64 cksum =
+ hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ // printf("Now trying range %d with %d, %s.\n", pos, cur_block_size,
+ // (cksum == prev_cksum) ? (u8*)"Yes" : (u8*) "Not");
+
+ /* continue until we fail or exceed length */
+ if (cksum == _prev_cksum) {
+
+ cur_block_size *= 2;
+
+ if (cur_block_size >= len - 1 - pos) break;
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ if (cur_block_size == MINIMAL_BLOCK_SIZE) {
+
+ /* we failed early on*/
+
+ pos += cur_block_size;
+
+ } else {
+
+ u32 cur_skip_len = (cur_block_size / 2 + pos < len)
+ ? (cur_block_size / 2)
+ : (len - pos - 1);
+
+ memset(inf_eff_map + pos, 0, cur_skip_len);
+
+ afl->skipdet_g->inf_prof->inf_skipped_bytes += cur_skip_len;
+
+ pos += cur_skip_len;
+
+ }
+
+ }
+
+ afl->skipdet_g->inf_prof->inf_execs_cost +=
+ (afl->fsrv.total_execs - pre_inf_exec);
+ afl->skipdet_g->inf_prof->inf_time_cost += (get_cur_time() - pre_inf_time);
+ // PFATAL("Done, now have %d bytes skipped, with exec %lld, time %lld.\n",
+ // afl->inf_skipped_bytes, afl->inf_execs_cost, afl->inf_time_cost);
+
+ } else
+
+ memset(inf_eff_map, 1, len);
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_INF] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_INF] += afl->stage_cur;
+
+ /****************************
+ * Quick Skip Effective Map *
+ ****************************/
+
+ /* Quick Effective Map Calculation */
+
+ afl->stage_short = "quick";
+ afl->stage_name = "quick eff";
+ afl->stage_cur = 0;
+ afl->stage_max = 32 * 1024;
+
+ orig_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ u32 before_skip_inf = afl->queued_items;
+
+ /* clean all the eff bytes, since previous eff bytes are already fuzzed */
+ u8 *skip_eff_map = afl->queue_cur->skipdet_e->skip_eff_map,
+ *done_inf_map = afl->queue_cur->skipdet_e->done_inf_map;
+
+ if (!skip_eff_map) {
+
+ skip_eff_map = (u8 *)ck_alloc(sizeof(u8) * len);
+ afl->queue_cur->skipdet_e->skip_eff_map = skip_eff_map;
+
+ } else {
+
+ memset(skip_eff_map, 0, sizeof(u8) * len);
+
+ }
+
+ /* restore the starting point */
+ if (!done_inf_map) {
+
+ done_inf_map = (u8 *)ck_alloc(sizeof(u8) * len);
+ afl->queue_cur->skipdet_e->done_inf_map = done_inf_map;
+
+ } else {
+
+ for (afl->stage_cur = 0; afl->stage_cur < len; afl->stage_cur++) {
+
+ if (done_inf_map[afl->stage_cur] == 0) break;
+
+ }
+
+ }
+
+ /* depending on the seed's performance, we could search eff bytes
+ for multiple rounds */
+
+ u8 eff_round_continue = 1, eff_round_done = 0, done_eff = 0, repeat_eff = 0,
+ fuzz_nearby = 0, *non_eff_bytes = 0;
+
+ u64 before_eff_execs = afl->fsrv.total_execs;
+
+ if (getenv("REPEAT_EFF")) repeat_eff = 1;
+ if (getenv("FUZZ_NEARBY")) fuzz_nearby = 1;
+
+ if (fuzz_nearby) {
+
+ non_eff_bytes = (u8 *)ck_alloc(sizeof(u8) * len);
+
+ // clean exec cksum
+ if (common_fuzz_stuff(afl, out_buf, len)) { return 0; }
+ prev_cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+
+ }
+
+ do {
+
+ eff_round_continue = 0;
+ afl->stage_max = 32 * 1024;
+
+ for (; afl->stage_cur < afl->stage_max && afl->stage_cur < len;
+ ++afl->stage_cur) {
+
+ afl->stage_cur_byte = afl->stage_cur;
+
+ if (!inf_eff_map[afl->stage_cur_byte] ||
+ skip_eff_map[afl->stage_cur_byte])
+ continue;
+
+ if (is_det_timeout(before_det_time, 1)) { goto cleanup_skipdet; }
+
+ u8 orig = out_buf[afl->stage_cur_byte], replace = rand_below(afl, 256);
+
+ while (replace == orig) {
+
+ replace = rand_below(afl, 256);
+
+ }
+
+ out_buf[afl->stage_cur_byte] = replace;
+
+ before_skip_inf = afl->queued_items;
+
+ if (common_fuzz_stuff(afl, out_buf, len)) { return 0; }
+
+ out_buf[afl->stage_cur_byte] = orig;
+
+ if (fuzz_nearby) {
+
+ if (prev_cksum ==
+ hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST)) {
+
+ non_eff_bytes[afl->stage_cur_byte] = 1;
+
+ }
+
+ }
+
+ if (afl->queued_items != before_skip_inf) {
+
+ skip_eff_map[afl->stage_cur_byte] = 1;
+ afl->queue_cur->skipdet_e->quick_eff_bytes += 1;
+
+ if (afl->stage_max < MAXIMUM_QUICK_EFF_EXECS) { afl->stage_max *= 2; }
+
+ if (afl->stage_max == MAXIMUM_QUICK_EFF_EXECS && repeat_eff)
+ eff_round_continue = 1;
+
+ }
+
+ done_inf_map[afl->stage_cur_byte] = 1;
+
+ }
+
+ afl->stage_cur = 0;
+ done_eff = 1;
+
+ if (++eff_round_done >= 8) break;
+
+ } while (eff_round_continue);
+
+ new_hit_cnt = afl->queued_items + afl->saved_crashes;
+
+ afl->stage_finds[STAGE_QUICK] += new_hit_cnt - orig_hit_cnt;
+ afl->stage_cycles[STAGE_QUICK] += (afl->fsrv.total_execs - before_eff_execs);
+
+cleanup_skipdet:
+
+ if (fuzz_nearby) {
+
+ u8 *nearby_bytes = (u8 *)ck_alloc(sizeof(u8) * len);
+
+ u32 i = 3;
+ while (i < len) {
+
+ // assume DWORD size, from i - 3 -> i + 3
+ if (skip_eff_map[i]) {
+
+ u32 fill_length = (i + 3 < len) ? 7 : len - i + 2;
+ memset(nearby_bytes + i - 3, 1, fill_length);
+ i += 3;
+
+ } else
+
+ i += 1;
+
+ }
+
+ for (i = 0; i < len; i++) {
+
+ if (nearby_bytes[i] && !non_eff_bytes[i]) skip_eff_map[i] = 1;
+
+ }
+
+ ck_free(nearby_bytes);
+ ck_free(non_eff_bytes);
+
+ }
+
+ if (done_eff) {
+
+ afl->queue_cur->skipdet_e->continue_inf = 0;
+ afl->queue_cur->skipdet_e->done_eff = 1;
+
+ } else {
+
+ afl->queue_cur->skipdet_e->continue_inf = 1;
+
+ }
+
+ return 1;
+
+}
+
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 5e736029..333d57b2 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -28,10 +28,6 @@
#include "afl-fuzz.h"
#include "envs.h"
-s8 interesting_8[] = {INTERESTING_8};
-s16 interesting_16[] = {INTERESTING_8, INTERESTING_16};
-s32 interesting_32[] = {INTERESTING_8, INTERESTING_16, INTERESTING_32};
-
char *power_names[POWER_SCHEDULES_NUM] = {"explore", "mmopt", "exploit",
"fast", "coe", "lin",
"quad", "rare", "seek"};
@@ -89,9 +85,8 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->w_end = 0.3;
afl->g_max = 5000;
afl->period_pilot_tmp = 5000.0;
- afl->schedule = FAST; /* Power schedule (default: FAST) */
+ afl->schedule = EXPLORE; /* Power schedule (default: EXPLORE)*/
afl->havoc_max_mult = HAVOC_MAX_MULT;
-
afl->clear_screen = 1; /* Window resized? */
afl->havoc_div = 1; /* Cycle count divisor for havoc */
afl->stage_name = "init"; /* Name of the current fuzz stage */
@@ -103,11 +98,12 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->stats_update_freq = 1;
afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000;
afl->stats_avg_exec = 0;
- afl->skip_deterministic = 1;
+ afl->skip_deterministic = 0;
afl->sync_time = SYNC_TIME;
afl->cmplog_lvl = 2;
afl->min_length = 1;
afl->max_length = MAX_FILE;
+ afl->switch_fuzz_mode = STRATEGY_SWITCH_TIME * 1000;
#ifndef NO_SPLICING
afl->use_splicing = 1;
#endif
@@ -140,6 +136,14 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->fsrv.child_pid = -1;
afl->fsrv.out_dir_fd = -1;
+ /* Init SkipDet */
+ afl->skipdet_g =
+ (struct skipdet_global *)ck_alloc(sizeof(struct skipdet_global));
+ afl->skipdet_g->inf_prof =
+ (struct inf_profile *)ck_alloc(sizeof(struct inf_profile));
+ afl->havoc_prof =
+ (struct havoc_profile *)ck_alloc(sizeof(struct havoc_profile));
+
init_mopt_globals(afl);
list_append(&afl_states, afl);
@@ -199,6 +203,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_exit_on_time =
(u8 *)get_afl_env(afl_environment_variables[i]);
+ } else if (!strncmp(env, "AFL_CRASHING_SEEDS_AS_NEW_CRASH",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_crashing_seeds_as_new_crash =
+ atoi((u8 *)get_afl_env(afl_environment_variables[i]));
+
} else if (!strncmp(env, "AFL_NO_AFFINITY",
afl_environment_variable_len)) {
@@ -261,6 +272,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_import_first =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_FINAL_SYNC",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_final_sync =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_CUSTOM_MUTATOR_ONLY",
afl_environment_variable_len)) {
@@ -275,6 +293,16 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_cmplog_only_new =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_DISABLE_REDUNDANT",
+
+ afl_environment_variable_len) ||
+ !strncmp(env, "AFL_NO_REDUNDANT",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_disable_redundant =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_NO_STARTUP_CALIBRATION",
afl_environment_variable_len)) {
@@ -301,6 +329,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_ignore_problems =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_IGNORE_SEED_PROBLEMS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_ignore_seed_problems =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_IGNORE_TIMEOUTS",
afl_environment_variable_len)) {
@@ -594,6 +629,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
}
+ } else if (!strncmp(env, "AFL_SHA1_FILENAMES",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_sha1_filenames =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
}
} else {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 07157bf7..ffe56cde 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -5,11 +5,12 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Dominik Meier <mail@dmnk.co>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>, and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -27,6 +28,50 @@
#include "envs.h"
#include <limits.h>
+static char fuzzing_state[4][12] = {"started :-)", "in progress", "final phase",
+ "finished..."};
+
+char *get_fuzzing_state(afl_state_t *afl) {
+
+ u64 cur_ms = get_cur_time();
+ u64 last_find = cur_ms - afl->last_find_time;
+ u64 cur_run_time = cur_ms - afl->start_time;
+ u64 cur_total_run_time = afl->prev_run_time + cur_run_time;
+
+ if (unlikely(afl->non_instrumented_mode)) {
+
+ return fuzzing_state[1];
+
+ } else if (unlikely(cur_run_time < 60 * 3 * 1000 ||
+
+ cur_total_run_time < 60 * 5 * 1000)) {
+
+ return fuzzing_state[0];
+
+ } else {
+
+ u64 last_find_100 = 100 * last_find;
+ u64 percent_cur = last_find_100 / cur_run_time;
+ u64 percent_total = last_find_100 / cur_total_run_time;
+
+ if (unlikely(percent_cur >= 80 && percent_total >= 80)) {
+
+ return fuzzing_state[3];
+
+ } else if (unlikely(percent_cur >= 55 && percent_total >= 55)) {
+
+ return fuzzing_state[2];
+
+ } else {
+
+ return fuzzing_state[1];
+
+ }
+
+ }
+
+}
+
/* Write fuzzer setup file */
void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
@@ -89,6 +134,12 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
}
+static bool starts_with(char *key, char *line) {
+
+ return strncmp(key, line, strlen(key)) == 0;
+
+}
+
/* load some of the existing stats file when resuming.*/
void load_stats_file(afl_state_t *afl) {
@@ -131,58 +182,84 @@ void load_stats_file(afl_state_t *afl) {
strcpy(keystring, lstartptr);
lptr++;
char *nptr;
- switch (lineno) {
-
- case 3:
- if (!strcmp(keystring, "run_time "))
- afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10);
- break;
- case 5:
- if (!strcmp(keystring, "cycles_done "))
- afl->queue_cycle =
- strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0;
- break;
- case 7:
- if (!strcmp(keystring, "execs_done "))
- afl->fsrv.total_execs = strtoull(lptr, &nptr, 10);
- break;
- case 10:
- if (!strcmp(keystring, "corpus_count ")) {
-
- u32 corpus_count = strtoul(lptr, &nptr, 10);
- if (corpus_count != afl->queued_items) {
-
- WARNF(
- "queue/ has been modified -- things might not work, you're "
- "on your own!");
-
- }
-
- }
-
- break;
- case 12:
- if (!strcmp(keystring, "corpus_found "))
- afl->queued_discovered = strtoul(lptr, &nptr, 10);
- break;
- case 13:
- if (!strcmp(keystring, "corpus_imported "))
- afl->queued_imported = strtoul(lptr, &nptr, 10);
- break;
- case 14:
- if (!strcmp(keystring, "max_depth "))
- afl->max_depth = strtoul(lptr, &nptr, 10);
- break;
- case 21:
- if (!strcmp(keystring, "saved_crashes "))
- afl->saved_crashes = strtoull(lptr, &nptr, 10);
- break;
- case 22:
- if (!strcmp(keystring, "saved_hangs "))
- afl->saved_hangs = strtoull(lptr, &nptr, 10);
- break;
- default:
- break;
+ if (starts_with("run_time", keystring)) {
+
+ afl->prev_run_time = 1000 * strtoull(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("cycles_done", keystring)) {
+
+ afl->queue_cycle =
+ strtoull(lptr, &nptr, 10) ? strtoull(lptr, &nptr, 10) + 1 : 0;
+
+ }
+
+ if (starts_with("calibration_time", keystring)) {
+
+ afl->calibration_time_us = strtoull(lptr, &nptr, 10) * 1000000;
+
+ }
+
+ if (starts_with("sync_time", keystring)) {
+
+ afl->sync_time_us = strtoull(lptr, &nptr, 10) * 1000000;
+
+ }
+
+ if (starts_with("trim_time", keystring)) {
+
+ afl->trim_time_us = strtoull(lptr, &nptr, 10) * 1000000;
+
+ }
+
+ if (starts_with("execs_done", keystring)) {
+
+ afl->fsrv.total_execs = strtoull(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("corpus_count", keystring)) {
+
+ u32 corpus_count = strtoul(lptr, &nptr, 10);
+ if (corpus_count != afl->queued_items) {
+
+ WARNF(
+ "queue/ has been modified -- things might not work, you're "
+ "on your own!");
+ sleep(3);
+
+ }
+
+ }
+
+ if (starts_with("corpus_found", keystring)) {
+
+ afl->queued_discovered = strtoul(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("corpus_imported", keystring)) {
+
+ afl->queued_imported = strtoul(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("max_depth", keystring)) {
+
+ afl->max_depth = strtoul(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("saved_crashes", keystring)) {
+
+ afl->saved_crashes = strtoull(lptr, &nptr, 10);
+
+ }
+
+ if (starts_with("saved_hangs", keystring)) {
+
+ afl->saved_hangs = strtoull(lptr, &nptr, 10);
}
@@ -206,11 +283,13 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
#endif
u64 cur_time = get_cur_time();
- u8 fn[PATH_MAX];
+ u8 fn_tmp[PATH_MAX];
+ u8 fn_final[PATH_MAX];
FILE *f;
- snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
- f = create_ffile(fn);
+ snprintf(fn_tmp, PATH_MAX, "%s/.fuzzer_stats_tmp", afl->out_dir);
+ snprintf(fn_final, PATH_MAX, "%s/fuzzer_stats", afl->out_dir);
+ f = create_ffile(fn_tmp);
/* Keep last values in case we're called from another context
where exec/sec stats and such are not readily available. */
@@ -242,6 +321,9 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
#ifndef __HAIKU__
if (getrusage(RUSAGE_CHILDREN, &rus)) { rus.ru_maxrss = 0; }
#endif
+ u64 runtime_ms = afl->prev_run_time + cur_time - afl->start_time;
+ u64 overhead_ms = (afl->calibration_time_us + afl->sync_time_us + afl->trim_time_us) / 1000;
+ if (!runtime_ms) { runtime_ms = 1; }
fprintf(
f,
@@ -252,6 +334,10 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"cycles_done : %llu\n"
"cycles_wo_finds : %llu\n"
"time_wo_finds : %llu\n"
+ "fuzz_time : %llu\n"
+ "calibration_time : %llu\n"
+ "sync_time : %llu\n"
+ "trim_time : %llu\n"
"execs_done : %llu\n"
"execs_per_sec : %0.02f\n"
"execs_ps_last_min : %0.02f\n"
@@ -289,18 +375,18 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"\n"
"target_mode : %s%s%s%s%s%s%s%s%s%s\n"
"command_line : %s\n",
- (afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
- (afl->prev_run_time + cur_time - afl->start_time) / 1000, (u32)getpid(),
+ (afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000,
+ runtime_ms / 1000, (u32)getpid(),
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
afl->longest_find_time > cur_time - afl->last_find_time
? afl->longest_find_time / 1000
: ((afl->start_time == 0 || afl->last_find_time == 0)
? 0
: (cur_time - afl->last_find_time) / 1000),
- afl->fsrv.total_execs,
- afl->fsrv.total_execs /
- ((double)(afl->prev_run_time + get_cur_time() - afl->start_time) /
- 1000),
+ (runtime_ms - MIN(runtime_ms, overhead_ms)) / 1000,
+ afl->calibration_time_us / 1000000, afl->sync_time_us / 1000000,
+ afl->trim_time_us / 1000000, afl->fsrv.total_execs,
+ afl->fsrv.total_execs / ((double)(runtime_ms) / 1000),
afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored,
afl->queued_discovered, afl->queued_imported, afl->queued_variable,
afl->max_depth, afl->current_entry, afl->pending_favored,
@@ -368,6 +454,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
}
fclose(f);
+ rename(fn_tmp, fn_final);
}
@@ -456,6 +543,44 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
}
+/* Log deterministic stage efficiency */
+
+void plot_profile_data(afl_state_t *afl, struct queue_entry *q) {
+
+ u64 current_ms = get_cur_time() - afl->start_time;
+
+ u32 current_edges = count_non_255_bytes(afl, afl->virgin_bits);
+ double det_finding_rate = (double)afl->havoc_prof->total_det_edge * 100.0 /
+ (double)current_edges,
+ det_time_rate = (double)afl->havoc_prof->total_det_time * 100.0 /
+ (double)current_ms;
+
+ u32 ndet_bits = 0;
+ for (u32 i = 0; i < afl->fsrv.map_size; i++) {
+
+ if (afl->skipdet_g->virgin_det_bits[i]) ndet_bits += 1;
+
+ }
+
+ double det_fuzzed_rate = (double)ndet_bits * 100.0 / (double)current_edges;
+
+ fprintf(afl->fsrv.det_plot_file,
+ "[%02lld:%02lld:%02lld] fuzz %d (%d), find %d/%d among %d(%02.2f) "
+ "and spend %lld/%lld(%02.2f), cover %02.2f yet, %d/%d undet bits, "
+ "continue %d.\n",
+ current_ms / 1000 / 3600, (current_ms / 1000 / 60) % 60,
+ (current_ms / 1000) % 60, afl->current_entry, q->fuzz_level,
+ afl->havoc_prof->edge_det_stage, afl->havoc_prof->edge_havoc_stage,
+ current_edges, det_finding_rate,
+ afl->havoc_prof->det_stage_time / 1000,
+ afl->havoc_prof->havoc_stage_time / 1000, det_time_rate,
+ det_fuzzed_rate, q->skipdet_e->undet_bits,
+ afl->skipdet_g->undet_bits_threshold, q->skipdet_e->continue_inf);
+
+ fflush(afl->fsrv.det_plot_file);
+
+}
+
/* Check terminal dimensions after resize. */
static void check_term_size(afl_state_t *afl) {
@@ -505,9 +630,9 @@ void show_stats_normal(afl_state_t *afl) {
cur_ms = get_cur_time();
- if (afl->most_time_key) {
+ if (afl->most_time_key && afl->queue_cycle) {
- if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+ if (afl->most_time * 1000 + afl->sync_time_us / 1000 < cur_ms - afl->start_time) {
afl->most_time_key = 2;
afl->stop_soon = 2;
@@ -516,7 +641,7 @@ void show_stats_normal(afl_state_t *afl) {
}
- if (afl->most_execs_key == 1) {
+ if (afl->most_execs_key == 1 && afl->queue_cycle) {
if (afl->most_execs <= afl->fsrv.total_execs) {
@@ -734,10 +859,29 @@ void show_stats_normal(afl_state_t *afl) {
if (unlikely(!banner[0])) {
char *si = "";
+ char *fuzzer_name;
+
if (afl->sync_id) { si = afl->sync_id; }
memset(banner, 0, sizeof(banner));
- banner_len = (afl->crash_mode ? 20 : 18) + strlen(VERSION) + strlen(si) +
- strlen(afl->power_name) + 4 + 6;
+
+ banner_len = strlen(VERSION) + strlen(si) + strlen(afl->power_name) + 4 + 6;
+
+ if (afl->crash_mode) {
+
+ fuzzer_name = "peruvian were-rabbit";
+
+ } else {
+
+ fuzzer_name = "american fuzzy lop";
+ if (banner_len + strlen(fuzzer_name) + strlen(afl->use_banner) > 75) {
+
+ fuzzer_name = "AFL";
+
+ }
+
+ }
+
+ banner_len += strlen(fuzzer_name);
if (strlen(afl->use_banner) + banner_len > 75) {
@@ -754,19 +898,18 @@ void show_stats_normal(afl_state_t *afl) {
if (afl->fsrv.nyx_mode) {
snprintf(banner + banner_pad, sizeof(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);
+ "%s%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN
+ "[%s] - Nyx",
+ afl->crash_mode ? cPIN : cYEL, fuzzer_name, si, afl->use_banner,
+ afl->power_name);
} else {
#endif
snprintf(banner + banner_pad, sizeof(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);
+ "%s%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN : cYEL, fuzzer_name, si, afl->use_banner,
+ afl->power_name);
#ifdef __linux__
@@ -774,6 +917,10 @@ void show_stats_normal(afl_state_t *afl) {
#endif
+ if (banner_pad)
+ for (u32 i = 0; i < banner_pad; ++i)
+ strcat(banner, " ");
+
}
SAYF("\n%s\n", banner);
@@ -995,7 +1142,7 @@ void show_stats_normal(afl_state_t *afl) {
sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_tmouts),
u_stringify_int(IB(1), afl->saved_tmouts),
- (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+ (afl->saved_tmouts >= KEEP_UNIQUE_HANG) ? "+" : "");
SAYF(bSTG bV bSTOP " total tmouts : " cRST "%-20s" bSTG bV "\n", tmp);
@@ -1010,7 +1157,7 @@ void show_stats_normal(afl_state_t *afl) {
} else if (likely(afl->skip_deterministic)) {
- strcpy(tmp, "disabled (default, enable with -D)");
+ strcpy(tmp, "disabled (-z switch used)");
} else {
@@ -1282,7 +1429,11 @@ void show_stats_normal(afl_state_t *afl) {
}
/* Last line */
- SAYF(SET_G1 "\n" bSTG bLB bH30 bH20 bH2 bRB bSTOP cRST RESET_G1);
+
+ SAYF(SET_G1 "\n" bSTG bLB bH cCYA bSTOP " strategy:" cPIN
+ " %s " bSTG bH10 cCYA bSTOP " state:" cPIN
+ " %s " bSTG bH2 bRB bSTOP cRST RESET_G1,
+ afl->fuzz_mode == 0 ? "explore" : "exploit", get_fuzzing_state(afl));
#undef IB
@@ -1309,9 +1460,9 @@ void show_stats_pizza(afl_state_t *afl) {
cur_ms = get_cur_time();
- if (afl->most_time_key) {
+ if (afl->most_time_key && afl->queue_cycle) {
- if (afl->most_time * 1000 < cur_ms - afl->start_time) {
+ if (afl->most_time * 1000 + afl->sync_time_us / 1000 < cur_ms - afl->start_time) {
afl->most_time_key = 2;
afl->stop_soon = 2;
@@ -1320,7 +1471,7 @@ void show_stats_pizza(afl_state_t *afl) {
}
- if (afl->most_execs_key == 1) {
+ if (afl->most_execs_key == 1 && afl->queue_cycle) {
if (afl->most_execs <= afl->fsrv.total_execs) {
@@ -1823,7 +1974,7 @@ void show_stats_pizza(afl_state_t *afl) {
sprintf(tmp, "%s (%s%s saved)", u_stringify_int(IB(0), afl->total_tmouts),
u_stringify_int(IB(1), afl->saved_tmouts),
- (afl->saved_hangs >= KEEP_UNIQUE_HANG) ? "+" : "");
+ (afl->saved_tmouts >= KEEP_UNIQUE_HANG) ? "+" : "");
SAYF(bSTG bV bSTOP " burned pizzas : " cRST "%-20s" bSTG bV
"\n",
@@ -2260,7 +2411,12 @@ void show_init_stats(afl_state_t *afl) {
stringify_int(IB(0), min_us), stringify_int(IB(1), max_us),
stringify_int(IB(2), avg_us));
- if (afl->timeout_given != 1) {
+ if (afl->timeout_given == 3) {
+
+ ACTF("Applying timeout settings from resumed session (%u ms).",
+ afl->fsrv.exec_tmout);
+
+ } else if (afl->timeout_given != 1) {
/* Figure out the appropriate timeout. The basic idea is: 5x average or
1x max, rounded up to EXEC_TM_ROUND ms and capped at 1 second.
@@ -2302,11 +2458,6 @@ void show_init_stats(afl_state_t *afl) {
afl->timeout_given = 1;
- } else if (afl->timeout_given == 3) {
-
- ACTF("Applying timeout settings from resumed session (%u ms).",
- afl->fsrv.exec_tmout);
-
} else {
ACTF("-t option specified. We'll use an exec timeout of %u ms.",
@@ -2329,3 +2480,26 @@ void show_init_stats(afl_state_t *afl) {
}
+void update_calibration_time(afl_state_t *afl, u64 *time) {
+
+ u64 cur = get_cur_time_us();
+ afl->calibration_time_us += cur - *time;
+ *time = cur;
+
+}
+
+void update_trim_time(afl_state_t *afl, u64 *time) {
+
+ u64 cur = get_cur_time_us();
+ afl->trim_time_us += cur - *time;
+ *time = cur;
+
+}
+
+void update_sync_time(afl_state_t *afl, u64 *time) {
+
+ u64 cur = get_cur_time_us();
+ afl->sync_time_us += cur - *time;
+ *time = cur;
+
+}
diff --git a/src/afl-fuzz-statsd.c b/src/afl-fuzz-statsd.c
index e835c8ea..2e42ea9b 100644
--- a/src/afl-fuzz-statsd.c
+++ b/src/afl-fuzz-statsd.c
@@ -223,7 +223,7 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) {
char tags[MAX_TAG_LEN * 2] = {0};
if (afl->statsd_tags_format) {
- snprintf(tags, MAX_TAG_LEN * 2, afl->statsd_tags_format, afl->use_banner,
+ snprintf(tags, MAX_TAG_LEN * 2, afl->statsd_tags_format, afl->sync_id,
VERSION);
}
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index 4339ddd2..70ab983c 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -5,11 +5,12 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
- Andrea Fioraldi <andreafioraldi@gmail.com>
+ Dominik Meier <mail@dmnk.co>,
+ Andrea Fioraldi <andreafioraldi@gmail.com>, and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -125,12 +126,20 @@ static void usage(u8 *argv0, int more_help) {
"Required parameters:\n"
" -i dir - input directory with test cases (or '-' to resume, "
- "also see AFL_AUTORESUME)\n"
+ "also see \n"
+ " AFL_AUTORESUME)\n"
" -o dir - output directory for fuzzer findings\n\n"
"Execution control settings:\n"
+ " -P strategy - set fix mutation strategy: explore (focus on new "
+ "coverage),\n"
+ " exploit (focus on triggering crashes). You can also "
+ "set a\n"
+ " number of seconds after without any finds it switches "
+ "to\n"
+ " exploit mode, and back on new coverage (default: %u)\n"
" -p schedule - power schedules compute a seed's performance score:\n"
- " fast(default), explore, exploit, seek, rare, mmopt, "
+ " explore(default), fast, exploit, seek, rare, mmopt, "
"coe, lin\n"
" quad -- see docs/FAQ.md for more information\n"
" -f file - location read by the fuzzed program (default: stdin "
@@ -157,25 +166,29 @@ static void usage(u8 *argv0, int more_help) {
"\n"
"Mutator settings:\n"
+ " -a type - target input format, \"text\" or \"binary\" (default: "
+ "generic)\n"
" -g minlength - set min length of generated fuzz input (default: 1)\n"
" -G maxlength - set max length of generated fuzz input (default: "
"%lu)\n"
- " -D - enable deterministic fuzzing (once per queue entry)\n"
" -L minutes - use MOpt(imize) mode and set the time limit for "
"entering the\n"
" pacemaker mode (minutes of no new finds). 0 = "
"immediately,\n"
" -1 = immediately and together with normal mutation.\n"
+ " Note: this option is usually not very effective\n"
" -c program - enable CmpLog by specifying a binary compiled for "
"it.\n"
" if using QEMU/FRIDA or the fuzzing target is "
"compiled\n"
- " for CmpLog then just use -c 0.\n"
+ " for CmpLog then use '-c 0'. To disable Cmplog use '-c "
+ "-'.\n"
" -l cmplog_opts - CmpLog configuration values (e.g. \"2ATR\"):\n"
" 1=small files, 2=larger files (default), 3=all "
"files,\n"
" A=arithmetic solving, T=transformational solving,\n"
- " R=random colorization bytes.\n\n"
+ " X=extreme transform solving, R=random colorization "
+ "bytes.\n\n"
"Fuzzing behavior settings:\n"
" -Z - sequential queue selection instead of weighted "
"random\n"
@@ -187,7 +200,8 @@ static void usage(u8 *argv0, int more_help) {
"Test settings:\n"
" -s seed - use a fixed seed for the RNG\n"
- " -V seconds - fuzz for a specified time then terminate\n"
+ " -V seconds - fuzz for a specified time then terminate (fuzz time "
+ "only!)\n"
" -E execs - fuzz for an approx. no. of total executions then "
"terminate\n"
" Note: not precise and can have several more "
@@ -200,7 +214,8 @@ static void usage(u8 *argv0, int more_help) {
" -F path - sync to a foreign fuzzer queue directory (requires "
"-M, can\n"
" be specified up to %u times)\n"
- // " -d - skip deterministic fuzzing in -M mode\n"
+ " -z - skip the enhanced deterministic fuzzing\n"
+ " (note that the old -d and -D flags are ignored.)\n"
" -T text - text banner to show on the screen\n"
" -I command - execute this command/script when a new crash is "
"found\n"
@@ -212,7 +227,8 @@ static void usage(u8 *argv0, int more_help) {
" -e ext - file extension for the fuzz test input file (if "
"needed)\n"
"\n",
- argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
+ argv0, STRATEGY_SWITCH_TIME, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE,
+ FOREIGN_SYNCS_MAX);
if (more_help > 1) {
@@ -248,10 +264,12 @@ static void usage(u8 *argv0, int more_help) {
"AFL_CYCLE_SCHEDULES: after completing a cycle, switch to a different -p schedule\n"
"AFL_DEBUG: extra debugging output for Python mode trimming\n"
"AFL_DEBUG_CHILD: do not suppress stdout/stderr from target\n"
+ "AFL_DISABLE_REDUNDANT: disable any queue item that is redundant\n"
"AFL_DISABLE_TRIM: disable the trimming of test cases\n"
"AFL_DUMB_FORKSRV: use fork server without feedback from target\n"
"AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n"
"AFL_EXIT_ON_TIME: exit when no new coverage is found within the specified time\n"
+ "AFL_EXIT_ON_SEED_ISSUES: exit on any kind of seed issues\n"
"AFL_EXPAND_HAVOC_NOW: immediately enable expand havoc mode (default: after 60\n"
" minutes and a cycle without finds)\n"
"AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n"
@@ -262,11 +280,14 @@ static void usage(u8 *argv0, int more_help) {
"AFL_IGNORE_PROBLEMS: do not abort fuzzing if an incorrect setup is detected\n"
"AFL_IGNORE_PROBLEMS_COVERAGE: if set in addition to AFL_IGNORE_PROBLEMS - also\n"
" ignore those libs for coverage\n"
+ "AFL_IGNORE_SEED_PROBLEMS: skip over crashes and timeouts in the seeds instead of\n"
+ " exiting\n"
"AFL_IGNORE_TIMEOUTS: do not process or save any timeouts\n"
"AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
"AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n"
"AFL_INPUT_LEN_MIN/AFL_INPUT_LEN_MAX: like -g/-G set min/max fuzz length produced\n"
- "AFL_PIZZA_MODE: 1 - enforce pizza mode, 0 - disable for April 1st\n"
+ "AFL_PIZZA_MODE: 1 - enforce pizza mode, -1 - disable for April 1st,\n"
+ " 0 (default) - activate on April 1st\n"
"AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc.\n"
" (default: SIGKILL)\n"
"AFL_FORK_SERVER_KILL_SIGNAL: Kill signal for the fork server on termination\n"
@@ -285,8 +306,14 @@ static void usage(u8 *argv0, int more_help) {
"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n"
"AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n"
"AFL_NO_STARTUP_CALIBRATION: no initial seed calibration, start fuzzing at once\n"
+ "AFL_NO_WARN_INSTABILITY: no warn about instability issues on startup calibration\n"
"AFL_NO_UI: switch status screen off\n"
-
+ "AFL_NYX_AUX_SIZE: size of the Nyx auxiliary buffer. Must be a multiple of 4096.\n"
+ " Increase this value in case the crash reports are truncated.\n"
+ " Default value is 4096.\n"
+ "AFL_NYX_DISABLE_SNAPSHOT_MODE: disable snapshot mode (must be supported by the agent)\n"
+ "AFL_NYX_LOG: output NYX hprintf messages to another file\n"
+ "AFL_NYX_REUSE_SNAPSHOT: reuse an existing Nyx root snapshot\n"
DYN_COLOR
"AFL_PATH: path to AFL support binaries\n"
@@ -295,8 +322,8 @@ static void usage(u8 *argv0, int more_help) {
PERSISTENT_MSG
- "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to the queue,\n"
- " but execute the post-processed one\n"
+ "AFL_POST_PROCESS_KEEP_ORIGINAL: save the file as it was prior post-processing to\n"
+ " the queue, but execute the post-processed one\n"
"AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n"
"AFL_TARGET_ENV: pass extra environment variables to target\n"
"AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n"
@@ -307,18 +334,18 @@ static void usage(u8 *argv0, int more_help) {
"AFL_STATSD_HOST: change default statsd host (default 127.0.0.1)\n"
"AFL_STATSD_PORT: change default statsd port (default: 8125)\n"
"AFL_STATSD_TAGS_FLAVOR: set statsd tags format (default: disable tags)\n"
- " Supported formats are: 'dogstatsd', 'librato',\n"
- " 'signalfx' and 'influxdb'\n"
+ " suported formats: dogstatsd, librato, signalfx, influxdb\n"
"AFL_SYNC_TIME: sync time between fuzzing instances (in minutes)\n"
+ "AFL_FINAL_SYNC: sync a final time when exiting (will delay the exit!)\n"
"AFL_NO_CRASH_README: do not create a README in the crashes directory\n"
"AFL_TESTCACHE_SIZE: use a cache for testcases, improves performance (in MB)\n"
"AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n"
"AFL_EARLY_FORKSERVER: force an early forkserver in an afl-clang-fast/\n"
" afl-clang-lto/afl-gcc-fast target\n"
- "AFL_PERSISTENT: enforce persistent mode (if __AFL_LOOP is in a shared lib\n"
- "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a .so)\n"
- "AFL_FUZZER_STATS_UPDATE_INTERVAL: interval to update fuzzer_stats file in seconds, "
- "(default: 60, minimum: 1)\n"
+ "AFL_PERSISTENT: enforce persistent mode (if __AFL_LOOP is in a shared lib)\n"
+ "AFL_DEFER_FORKSRV: enforced deferred forkserver (__AFL_INIT is in a shared lib)\n"
+ "AFL_FUZZER_STATS_UPDATE_INTERVAL: interval to update fuzzer_stats file in\n"
+ " seconds (default: 60, minimum: 1)\n"
"\n"
);
@@ -357,6 +384,10 @@ static void usage(u8 *argv0, int more_help) {
SAYF("Compiled with NO_SPLICING.\n");
#endif
+#ifdef FANCY_BOXES_NO_UTF
+ SAYF("Compiled without UTF-8 support for line rendering in status screen.\n");
+#endif
+
#ifdef PROFILING
SAYF("Compiled with PROFILING.\n");
#endif
@@ -373,6 +404,12 @@ static void usage(u8 *argv0, int more_help) {
SAYF("Compiled with _AFL_DOCUMENT_MUTATIONS.\n");
#endif
+#ifdef _AFL_SPECIAL_PERFORMANCE
+ SAYF(
+ "Compiled with special performance options for this specific system, it "
+ "might not work on other platforms!\n");
+#endif
+
SAYF("For additional help please consult %s/README.md :)\n\n", doc_path);
exit(1);
@@ -458,6 +495,22 @@ int main(int argc, char **argv_orig, char **envp) {
struct timeval tv;
struct timezone tz;
+ doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
+
+ if (argc > 1 && strcmp(argv_orig[1], "--version") == 0) {
+
+ printf("afl-fuzz" VERSION "\n");
+ exit(0);
+
+ }
+
+ if (argc > 1 && strcmp(argv_orig[1], "--help") == 0) {
+
+ usage(argv_orig[0], 1);
+ exit(0);
+
+ }
+
#if defined USE_COLOR && defined ALWAYS_COLORED
if (getenv("AFL_NO_COLOR") || getenv("AFL_NO_COLOUR")) {
@@ -487,21 +540,72 @@ int main(int argc, char **argv_orig, char **envp) {
SAYF(cCYA "afl-fuzz" VERSION cRST
" based on afl by Michal Zalewski and a large online community\n");
- doc_path = access(DOC_PATH, F_OK) != 0 ? (u8 *)"docs" : (u8 *)DOC_PATH;
-
gettimeofday(&tv, &tz);
rand_set_seed(afl, tv.tv_sec ^ tv.tv_usec ^ getpid());
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
- 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:YZ")) >
- 0) {
+ // still available: HjJkKqruvwz
+ while ((opt = getopt(argc, argv,
+ "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
+ "T:UV:WXx:YzZ")) > 0) {
switch (opt) {
+ case 'a':
+
+ if (!stricmp(optarg, "text") || !stricmp(optarg, "ascii") ||
+ !stricmp(optarg, "txt") || !stricmp(optarg, "asc")) {
+
+ afl->input_mode = 1;
+
+ } else if (!stricmp(optarg, "bin") || !stricmp(optarg, "binary")) {
+
+ afl->input_mode = 2;
+
+ } else if (!stricmp(optarg, "def") || !stricmp(optarg, "default")) {
+
+ afl->input_mode = 0;
+
+ } else {
+
+ FATAL("-a input mode needs to be \"text\" or \"binary\".");
+
+ }
+
+ break;
+
+ case 'P':
+ if (!stricmp(optarg, "explore") || !stricmp(optarg, "exploration")) {
+
+ afl->fuzz_mode = 0;
+ afl->switch_fuzz_mode = 0;
+
+ } else if (!stricmp(optarg, "exploit") ||
+
+ !stricmp(optarg, "exploitation")) {
+
+ afl->fuzz_mode = 1;
+ afl->switch_fuzz_mode = 0;
+
+ } else {
+
+ if ((afl->switch_fuzz_mode = (u32)atoi(optarg)) > INT_MAX) {
+
+ FATAL(
+ "Parameter for option -P must be \"explore\", \"exploit\" or a "
+ "number!");
+
+ } else {
+
+ afl->switch_fuzz_mode *= 1000;
+
+ }
+
+ }
+
+ break;
+
case 'g':
afl->min_length = atoi(optarg);
break;
@@ -534,8 +638,23 @@ int main(int argc, char **argv_orig, char **envp) {
case 'c': {
- afl->shm.cmplog_mode = 1;
- afl->cmplog_binary = ck_strdup(optarg);
+ if (strcmp(optarg, "-") == 0) {
+
+ if (afl->shm.cmplog_mode) {
+
+ ACTF("Disabling cmplog again because of '-c -'.");
+ afl->shm.cmplog_mode = 0;
+ afl->cmplog_binary = NULL;
+
+ }
+
+ } else {
+
+ afl->shm.cmplog_mode = 1;
+ afl->cmplog_binary = ck_strdup(optarg);
+
+ }
+
break;
}
@@ -845,12 +964,15 @@ int main(int argc, char **argv_orig, char **envp) {
break;
- case 'D': /* enforce deterministic */
+ case 'd':
+ case 'D': /* old deterministic */
- afl->skip_deterministic = 0;
+ WARNF(
+ "Parameters -d and -D are deprecated, a new enhanced deterministic "
+ "fuzzing is active by default, to disable it use -z");
break;
- case 'd': /* skip deterministic */
+ case 'z': /* no deterministic */
afl->skip_deterministic = 1;
break;
@@ -1056,10 +1178,18 @@ int main(int argc, char **argv_orig, char **envp) {
case 'A':
afl->cmplog_enable_arith = 1;
break;
+ case 's':
+ case 'S':
+ afl->cmplog_enable_scale = 1;
+ break;
case 't':
case 'T':
afl->cmplog_enable_transform = 1;
break;
+ case 'x':
+ case 'X':
+ afl->cmplog_enable_xtreme_transform = 1;
+ break;
case 'r':
case 'R':
afl->cmplog_random_colorization = 1;
@@ -1108,6 +1238,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ afl->old_seed_selection = 1;
u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000;
if ((s32)limit_time_puppet2 < afl->limit_time_puppet) {
@@ -1221,6 +1352,10 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ WARNF(
+ "Note that the MOpt mode is not maintained and is not as effective "
+ "as normal havoc mode.");
+
} break;
case 'h':
@@ -1242,6 +1377,12 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (afl->sync_id && strcmp(afl->sync_id, "addseeds") == 0) {
+
+ FATAL("-M/-S name 'addseeds' is a reserved name, choose something else");
+
+ }
+
if (afl->is_main_node == 1 && afl->schedule != FAST &&
afl->schedule != EXPLORE) {
@@ -1296,11 +1437,11 @@ int main(int argc, char **argv_orig, char **envp) {
}
#endif
+
+ // silently disable deterministic mutation if custom mutators are used
if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
- FATAL(
- "Using -D determinstic fuzzing is incompatible with "
- "AFL_CUSTOM_MUTATOR_ONLY!");
+ afl->skip_deterministic = 1;
}
@@ -1396,9 +1537,9 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->sync_id) {
- if (strlen(afl->sync_id) > 24) {
+ if (strlen(afl->sync_id) > 50) {
- FATAL("sync_id max length is 24 characters");
+ FATAL("sync_id max length is 50 characters");
}
@@ -1424,7 +1565,11 @@ int main(int argc, char **argv_orig, char **envp) {
setenv("__AFL_OUT_DIR", afl->out_dir, 1);
- if (get_afl_env("AFL_DISABLE_TRIM")) { afl->disable_trim = 1; }
+ if (get_afl_env("AFL_DISABLE_TRIM") || get_afl_env("AFL_NO_TRIM")) {
+
+ afl->disable_trim = 1;
+
+ }
if (getenv("AFL_NO_UI") && getenv("AFL_FORCE_UI")) {
@@ -1436,8 +1581,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (!afl->use_banner) { afl->use_banner = argv[optind]; }
- if (afl->shm.cmplog_mode &&
- (!strcmp("-", afl->cmplog_binary) || !strcmp("0", afl->cmplog_binary))) {
+ if (afl->shm.cmplog_mode && strcmp("0", afl->cmplog_binary) == 0) {
afl->cmplog_binary = strdup(argv[optind]);
@@ -1622,6 +1766,34 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ // Marker: ADD_TO_INJECTIONS
+ if (getenv("AFL_LLVM_INJECTIONS_ALL") || getenv("AFL_LLVM_INJECTIONS_SQL") ||
+ getenv("AFL_LLVM_INJECTIONS_LDAP") || getenv("AFL_LLVM_INJECTIONS_XSS")) {
+
+ OKF("Adding injection tokens to dictionary.");
+ if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
+ getenv("AFL_LLVM_INJECTIONS_SQL")) {
+
+ add_extra(afl, "'\"\"'", 4);
+
+ }
+
+ if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
+ getenv("AFL_LLVM_INJECTIONS_LDAP")) {
+
+ add_extra(afl, "*)(1=*))(|", 10);
+
+ }
+
+ if (getenv("AFL_LLVM_INJECTIONS_ALL") ||
+ getenv("AFL_LLVM_INJECTIONS_XSS")) {
+
+ add_extra(afl, "1\"><\"", 5);
+
+ }
+
+ }
+
OKF("Generating fuzz data with a length of min=%u max=%u", afl->min_length,
afl->max_length);
u32 min_alloc = MAX(64U, afl->min_length);
@@ -1633,6 +1805,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_realloc(AFL_BUF_PARAM(ex), min_alloc);
afl->fsrv.use_fauxsrv = afl->non_instrumented_mode == 1 || afl->no_forkserver;
+ afl->fsrv.max_length = afl->max_length;
#ifdef __linux__
if (!afl->fsrv.nyx_mode) {
@@ -1657,6 +1830,10 @@ int main(int argc, char **argv_orig, char **envp) {
check_cpu_governor(afl);
#endif
+ #ifdef __APPLE__
+ setenv("DYLD_NO_PIE", "1", 0);
+ #endif
+
if (getenv("LD_PRELOAD")) {
WARNF(
@@ -1746,16 +1923,6 @@ int main(int argc, char **argv_orig, char **envp) {
check_if_tty(afl);
if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; }
- if (afl->afl_env.afl_custom_mutator_only) {
-
- /* This ensures we don't proceed to havoc/splice */
- afl->custom_only = 1;
-
- /* Ensure we also skip all deterministic steps */
- afl->skip_deterministic = 1;
-
- }
-
get_core_count(afl);
atexit(at_exit);
@@ -1766,6 +1933,15 @@ int main(int argc, char **argv_orig, char **envp) {
bind_to_free_cpu(afl);
#endif /* HAVE_AFFINITY */
+ #ifdef __linux__
+ if (afl->fsrv.nyx_mode && afl->fsrv.nyx_bind_cpu_id == 0xFFFFFFFF) {
+
+ afl->fsrv.nyx_bind_cpu_id = 0;
+
+ }
+
+ #endif
+
#ifdef __HAIKU__
/* Prioritizes performance over power saving */
set_scheduler_mode(SCHEDULER_MODE_LOW_LATENCY);
@@ -1816,7 +1992,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- {
+ if (!getenv("AFL_CUSTOM_INFO_PROGRAM_ARGV")) {
u8 envbuf[8096] = "", tmpbuf[8096] = "";
for (s32 i = optind + 1; i < argc; ++i) {
@@ -1847,10 +2023,41 @@ int main(int argc, char **argv_orig, char **envp) {
}
- setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR
+ if (!getenv("AFL_CUSTOM_INFO_OUT")) {
+
+ setenv("AFL_CUSTOM_INFO_OUT", afl->out_dir, 1); // same as __AFL_OUT_DIR
+
+ }
setup_custom_mutators(afl);
+ if (afl->afl_env.afl_custom_mutator_only) {
+
+ if (!afl->custom_mutators_count) {
+
+ if (afl->shm.cmplog_mode) {
+
+ WARNF(
+ "No custom mutator loaded, using AFL_CUSTOM_MUTATOR_ONLY is "
+ "pointless and only allowed now to allow experiments with CMPLOG.");
+
+ } else {
+
+ FATAL(
+ "No custom mutator loaded but AFL_CUSTOM_MUTATOR_ONLY specified.");
+
+ }
+
+ }
+
+ /* This ensures we don't proceed to havoc/splice */
+ afl->custom_only = 1;
+
+ /* Ensure we also skip all deterministic steps */
+ afl->skip_deterministic = 1;
+
+ }
+
if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
if (afl->custom_only) {
@@ -1874,6 +2081,17 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ /* Simply code if AFL_TMPDIR is used or not */
+ if (!afl->afl_env.afl_tmpdir) {
+
+ afl->tmp_dir = afl->out_dir;
+
+ } else {
+
+ afl->tmp_dir = afl->afl_env.afl_tmpdir;
+
+ }
+
write_setup_file(afl, argc, argv);
setup_cmdline_file(afl, argv + optind);
@@ -1886,8 +2104,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (!afl->timeout_given) { find_timeout(afl); } // only for resumes!
- if ((afl->tmp_dir = afl->afl_env.afl_tmpdir) != NULL &&
- !afl->in_place_resume) {
+ if (afl->afl_env.afl_tmpdir && !afl->in_place_resume) {
char tmpfile[PATH_MAX];
@@ -1912,10 +2129,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
- } else {
-
- afl->tmp_dir = afl->out_dir;
-
}
/* If we don't have a file name chosen yet, use a safe default. */
@@ -1987,7 +2200,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- afl->fsrv.persistent_record_dir = alloc_printf("%s/crashes", afl->out_dir);
+ afl->fsrv.persistent_record_dir = alloc_printf("%s", afl->out_dir);
}
@@ -2253,7 +2466,7 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
- ACTF("skipping initial seed calibration due option override");
+ ACTF("skipping initial seed calibration due option override!");
usleep(1000);
}
@@ -2294,10 +2507,18 @@ int main(int argc, char **argv_orig, char **envp) {
for (entry = 0; entry < afl->queued_items; ++entry)
if (!afl->queue_buf[entry]->disabled)
- if (afl->queue_buf[entry]->exec_us > max_ms)
- max_ms = afl->queue_buf[entry]->exec_us;
+ if ((afl->queue_buf[entry]->exec_us / 1000) > max_ms)
+ max_ms = afl->queue_buf[entry]->exec_us / 1000;
+
+ // Add 20% as a safety margin, capped to exec_tmout given in -t option
+ max_ms *= 1.2;
+ if (max_ms > afl->fsrv.exec_tmout) max_ms = afl->fsrv.exec_tmout;
+
+ // Ensure that there is a sensible timeout even for very fast binaries
+ if (max_ms < 5) max_ms = 5;
afl->fsrv.exec_tmout = max_ms;
+ afl->timeout_given = 1;
}
@@ -2330,8 +2551,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
// (void)nice(-20); // does not improve the speed
- // real start time, we reset, so this works correctly with -V
- afl->start_time = get_cur_time();
#ifdef INTROSPECTION
u32 prev_saved_crashes = 0, prev_saved_tmouts = 0;
@@ -2352,6 +2571,9 @@ int main(int argc, char **argv_orig, char **envp) {
OKF("Writing mutation introspection to '%s'", ifn);
#endif
+ // real start time, we reset, so this works correctly with -V
+ afl->start_time = get_cur_time();
+
while (likely(!afl->stop_soon)) {
cull_queue(afl);
@@ -2590,22 +2812,52 @@ int main(int argc, char **argv_orig, char **envp) {
if (likely(!afl->old_seed_selection)) {
- if (unlikely(prev_queued_items < afl->queued_items ||
- afl->reinit_table)) {
+ if (likely(afl->pending_favored && afl->smallest_favored >= 0)) {
- // we have new queue entries since the last run, recreate alias table
- prev_queued_items = afl->queued_items;
- create_alias_table(afl);
+ afl->current_entry = afl->smallest_favored;
- }
+ /*
- do {
+ } else {
- afl->current_entry = select_next_queue_entry(afl);
+ for (s32 iter = afl->queued_items - 1; iter >= 0; --iter)
+ {
- } while (unlikely(afl->current_entry >= afl->queued_items));
+ if (unlikely(afl->queue_buf[iter]->favored &&
+ !afl->queue_buf[iter]->was_fuzzed)) {
- afl->queue_cur = afl->queue_buf[afl->current_entry];
+ afl->current_entry = iter;
+ break;
+
+ }
+
+ }
+
+ */
+
+ afl->queue_cur = afl->queue_buf[afl->current_entry];
+
+ } else {
+
+ if (unlikely(prev_queued_items < afl->queued_items ||
+ afl->reinit_table)) {
+
+ // we have new queue entries since the last run, recreate alias
+ // table
+ prev_queued_items = afl->queued_items;
+ create_alias_table(afl);
+
+ }
+
+ do {
+
+ afl->current_entry = select_next_queue_entry(afl);
+
+ } while (unlikely(afl->current_entry >= afl->queued_items));
+
+ afl->queue_cur = afl->queue_buf[afl->current_entry];
+
+ }
}
@@ -2667,13 +2919,34 @@ int main(int argc, char **argv_orig, char **envp) {
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
+ u64 cur_time = get_cur_time();
+
+ if (likely(afl->switch_fuzz_mode && afl->fuzz_mode == 0 &&
+ !afl->non_instrumented_mode) &&
+ unlikely(cur_time > (likely(afl->last_find_time) ? afl->last_find_time
+ : afl->start_time) +
+ afl->switch_fuzz_mode)) {
+
+ if (afl->afl_env.afl_no_ui) {
+
+ ACTF(
+ "No new coverage found for %llu seconds, switching to exploitation "
+ "strategy.",
+ afl->switch_fuzz_mode / 1000);
+
+ }
+
+ afl->fuzz_mode = 1;
+
+ }
+
if (likely(!afl->stop_soon && afl->sync_id)) {
if (likely(afl->skip_deterministic)) {
if (unlikely(afl->is_main_node)) {
- if (unlikely(get_cur_time() >
+ if (unlikely(cur_time >
(afl->sync_time >> 1) + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % (SYNC_INTERVAL / 3))) {
@@ -2686,7 +2959,7 @@ int main(int argc, char **argv_orig, char **envp) {
} else {
- if (unlikely(get_cur_time() > afl->sync_time + afl->last_sync_time)) {
+ if (unlikely(cur_time > afl->sync_time + afl->last_sync_time)) {
if (!(sync_interval_cnt++ % SYNC_INTERVAL)) { sync_fuzzers(afl); }
@@ -2769,6 +3042,16 @@ stop_fuzzing:
time_spent_working / afl->fsrv.total_execs);
#endif
+ if (afl->afl_env.afl_final_sync) {
+
+ SAYF(cYEL "[!] " cRST
+ "\nPerforming final sync, this make take some time ...\n");
+ sync_fuzzers(afl);
+ write_bitmap(afl);
+ SAYF(cYEL "[!] " cRST "Done!\n\n");
+
+ }
+
if (afl->is_main_node) {
u8 path[PATH_MAX];
@@ -2780,6 +3063,11 @@ stop_fuzzing:
if (frida_afl_preload) { ck_free(frida_afl_preload); }
fclose(afl->fsrv.plot_file);
+
+ #ifdef INTROSPECTION
+ fclose(afl->fsrv.det_plot_file);
+ #endif
+
destroy_queue(afl);
destroy_extras(afl);
destroy_custom_mutators(afl);
@@ -2795,7 +3083,7 @@ stop_fuzzing:
afl_fsrv_deinit(&afl->fsrv);
/* remove tmpfile */
- if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) {
+ if (!afl->in_place_resume && afl->fsrv.out_file) {
(void)unlink(afl->fsrv.out_file);
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
index 4f851099..6a3bd037 100644
--- a/src/afl-gotcpu.c
+++ b/src/afl-gotcpu.c
@@ -5,11 +5,11 @@
Originally written by Michal Zalewski
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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 420dd817..578552ba 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -5,11 +5,11 @@
Written by Marc Heuse <mh@mh-sec.de> for AFL++
Maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de>
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de>
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <domenukk@gmail.com>
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -23,7 +23,9 @@
*/
#define AFL_MAIN
-#define _GNU_SOURCE
+#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
+#endif
#include "config.h"
#include "types.h"
@@ -37,6 +39,7 @@
#include <time.h>
#include <ctype.h>
#include <fcntl.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -45,11 +48,6 @@
#include <dirent.h>
-#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || \
- defined(__DragonFly__)
- #include <limits.h>
-#endif
-
#ifdef __APPLE__
#include <sys/syslimits.h>
#endif
@@ -280,7 +278,7 @@ int main(int argc, char **argv) {
if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1;
if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD");
- if (!afl_path || !*afl_path) afl_path = "/usr/local/lib/afl";
+ if (!afl_path || !*afl_path) afl_path = AFL_PATH;
setenv("AFL_LD_CALLER", "1", 1);
diff --git a/src/afl-performance.c b/src/afl-performance.c
index 04507410..6c6e3c8b 100644
--- a/src/afl-performance.c
+++ b/src/afl-performance.c
@@ -1,31 +1,18 @@
-/*
- Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org)
-
- To the extent possible under law, the author has dedicated all copyright
- and related and neighboring rights to this software to the public domain
- worldwide. This software is distributed without any warranty.
-
- See <https://creativecommons.org/publicdomain/zero/1.0/>.
-
- This is xoshiro256++ 1.0, one of our all-purpose, rock-solid generators.
- It has excellent (sub-ns) speed, a state (256 bits) that is large
- enough for any parallel application, and it passes all tests we are
- aware of.
-
- For generating just floating-point numbers, xoshiro256+ is even faster.
-
- The state must be seeded so that it is not everywhere zero. If you have
- a 64-bit seed, we suggest to seed a splitmix64 generator and use its
- output to fill s[].
-*/
-
#include <stdint.h>
#include "afl-fuzz.h"
#include "types.h"
-#define XXH_INLINE_ALL
-#include "xxhash.h"
-#undef XXH_INLINE_ALL
+#ifdef _HAVE_AVX2
+ #define T1HA0_AESNI_AVAILABLE 1
+ #define T1HA_USE_FAST_ONESHOT_READ 1
+ #define T1HA_USE_INDIRECT_FUNCTIONS 1
+ #define T1HA_IA32AES_NAME XXH3_64bits
+ #include "t1ha0_ia32aes_b.h"
+#else
+ #define XXH_INLINE_ALL
+ #include "xxhash.h"
+ #undef XXH_INLINE_ALL
+#endif
void rand_set_seed(afl_state_t *afl, s64 init_seed) {
@@ -108,3 +95,313 @@ inline u64 hash64(u8 *key, u32 len, u64 seed) {
}
+// Public domain SHA1 implementation copied from:
+// https://github.com/x42/liboauth/blob/7001b8256cd654952ec2515b055d2c5b243be600/src/sha1.c
+
+/* This code is public-domain - it is based on libcrypt
+ * placed in the public domain by Wei Dai and other contributors.
+ */
+// gcc -Wall -DSHA1TEST -o sha1test sha1.c && ./sha1test
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __BIG_ENDIAN__
+ #define SHA_BIG_ENDIAN
+#elif defined __LITTLE_ENDIAN__
+/* override */
+#elif defined __BYTE_ORDER
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #define SHA_BIG_ENDIAN
+ #endif
+#else // ! defined __LITTLE_ENDIAN__
+ #include <endian.h> // machine/endian.h
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ #define SHA_BIG_ENDIAN
+ #endif
+#endif
+
+/* header */
+
+#define HASH_LENGTH 20
+#define BLOCK_LENGTH 64
+
+typedef struct sha1nfo {
+
+ uint32_t buffer[BLOCK_LENGTH / 4];
+ uint32_t state[HASH_LENGTH / 4];
+ uint32_t byteCount;
+ uint8_t bufferOffset;
+ uint8_t keyBuffer[BLOCK_LENGTH];
+ uint8_t innerHash[HASH_LENGTH];
+
+} sha1nfo;
+
+/* public API - prototypes - TODO: doxygen*/
+
+/**
+ */
+void sha1_init(sha1nfo *s);
+/**
+ */
+void sha1_writebyte(sha1nfo *s, uint8_t data);
+/**
+ */
+void sha1_write(sha1nfo *s, const char *data, size_t len);
+/**
+ */
+uint8_t *sha1_result(sha1nfo *s);
+/**
+ */
+void sha1_initHmac(sha1nfo *s, const uint8_t *key, int keyLength);
+/**
+ */
+uint8_t *sha1_resultHmac(sha1nfo *s);
+
+/* code */
+#define SHA1_K0 0x5a827999
+#define SHA1_K20 0x6ed9eba1
+#define SHA1_K40 0x8f1bbcdc
+#define SHA1_K60 0xca62c1d6
+
+void sha1_init(sha1nfo *s) {
+
+ s->state[0] = 0x67452301;
+ s->state[1] = 0xefcdab89;
+ s->state[2] = 0x98badcfe;
+ s->state[3] = 0x10325476;
+ s->state[4] = 0xc3d2e1f0;
+ s->byteCount = 0;
+ s->bufferOffset = 0;
+
+}
+
+uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
+
+ return ((number << bits) | (number >> (32 - bits)));
+
+}
+
+void sha1_hashBlock(sha1nfo *s) {
+
+ uint8_t i;
+ uint32_t a, b, c, d, e, t;
+
+ a = s->state[0];
+ b = s->state[1];
+ c = s->state[2];
+ d = s->state[3];
+ e = s->state[4];
+ for (i = 0; i < 80; i++) {
+
+ if (i >= 16) {
+
+ t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^
+ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15];
+ s->buffer[i & 15] = sha1_rol32(t, 1);
+
+ }
+
+ if (i < 20) {
+
+ t = (d ^ (b & (c ^ d))) + SHA1_K0;
+
+ } else if (i < 40) {
+
+ t = (b ^ c ^ d) + SHA1_K20;
+
+ } else if (i < 60) {
+
+ t = ((b & c) | (d & (b | c))) + SHA1_K40;
+
+ } else {
+
+ t = (b ^ c ^ d) + SHA1_K60;
+
+ }
+
+ t += sha1_rol32(a, 5) + e + s->buffer[i & 15];
+ e = d;
+ d = c;
+ c = sha1_rol32(b, 30);
+ b = a;
+ a = t;
+
+ }
+
+ s->state[0] += a;
+ s->state[1] += b;
+ s->state[2] += c;
+ s->state[3] += d;
+ s->state[4] += e;
+
+}
+
+void sha1_addUncounted(sha1nfo *s, uint8_t data) {
+
+ uint8_t *const b = (uint8_t *)s->buffer;
+#ifdef SHA_BIG_ENDIAN
+ b[s->bufferOffset] = data;
+#else
+ b[s->bufferOffset ^ 3] = data;
+#endif
+ s->bufferOffset++;
+ if (s->bufferOffset == BLOCK_LENGTH) {
+
+ sha1_hashBlock(s);
+ s->bufferOffset = 0;
+
+ }
+
+}
+
+void sha1_writebyte(sha1nfo *s, uint8_t data) {
+
+ ++s->byteCount;
+ sha1_addUncounted(s, data);
+
+}
+
+void sha1_write(sha1nfo *s, const char *data, size_t len) {
+
+ for (; len--;)
+ sha1_writebyte(s, (uint8_t)*data++);
+
+}
+
+void sha1_pad(sha1nfo *s) {
+
+ // Implement SHA-1 padding (fips180-2 §5.1.1)
+
+ // Pad with 0x80 followed by 0x00 until the end of the block
+ sha1_addUncounted(s, 0x80);
+ while (s->bufferOffset != 56)
+ sha1_addUncounted(s, 0x00);
+
+ // Append length in the last 8 bytes
+ sha1_addUncounted(s, 0); // We're only using 32 bit lengths
+ sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
+ sha1_addUncounted(s, 0); // So zero pad the top bits
+ sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
+ sha1_addUncounted(
+ s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
+ sha1_addUncounted(s, s->byteCount >> 13); // byte.
+ sha1_addUncounted(s, s->byteCount >> 5);
+ sha1_addUncounted(s, s->byteCount << 3);
+
+}
+
+uint8_t *sha1_result(sha1nfo *s) {
+
+ // Pad to complete the last block
+ sha1_pad(s);
+
+#ifndef SHA_BIG_ENDIAN
+ // Swap byte order back
+ int i;
+ for (i = 0; i < 5; i++) {
+
+ s->state[i] = (((s->state[i]) << 24) & 0xff000000) |
+ (((s->state[i]) << 8) & 0x00ff0000) |
+ (((s->state[i]) >> 8) & 0x0000ff00) |
+ (((s->state[i]) >> 24) & 0x000000ff);
+
+ }
+
+#endif
+
+ // Return pointer to hash (20 characters)
+ return (uint8_t *)s->state;
+
+}
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+
+void sha1_initHmac(sha1nfo *s, const uint8_t *key, int keyLength) {
+
+ uint8_t i;
+ memset(s->keyBuffer, 0, BLOCK_LENGTH);
+ if (keyLength > BLOCK_LENGTH) {
+
+ // Hash long keys
+ sha1_init(s);
+ for (; keyLength--;)
+ sha1_writebyte(s, *key++);
+ memcpy(s->keyBuffer, sha1_result(s), HASH_LENGTH);
+
+ } else {
+
+ // Block length keys are used as is
+ memcpy(s->keyBuffer, key, keyLength);
+
+ }
+
+ // Start inner hash
+ sha1_init(s);
+ for (i = 0; i < BLOCK_LENGTH; i++) {
+
+ sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD);
+
+ }
+
+}
+
+uint8_t *sha1_resultHmac(sha1nfo *s) {
+
+ uint8_t i;
+ // Complete inner hash
+ memcpy(s->innerHash, sha1_result(s), HASH_LENGTH);
+ // Calculate outer hash
+ sha1_init(s);
+ for (i = 0; i < BLOCK_LENGTH; i++)
+ sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD);
+ for (i = 0; i < HASH_LENGTH; i++)
+ sha1_writebyte(s, s->innerHash[i]);
+ return sha1_result(s);
+
+}
+
+// End public domain SHA1 implementation
+
+void sha1(const u8 *data, size_t len, u8 *out) {
+
+ sha1nfo s;
+ sha1_init(&s);
+ sha1_write(&s, (const char *)data, len);
+ memcpy(out, sha1_result(&s), HASH_LENGTH);
+
+}
+
+char *sha1_hex(const u8 *data, size_t len) {
+
+ u8 digest[HASH_LENGTH];
+ sha1(data, len, digest);
+ u8 *hex = ck_alloc(HASH_LENGTH * 2 + 1);
+ for (size_t i = 0; i < HASH_LENGTH; ++i) {
+
+ sprintf((char *)(hex + i * 2), "%02x", digest[i]);
+
+ }
+
+ return hex;
+
+}
+
+char *sha1_hex_for_file(const char *fname, u32 len) {
+
+ int fd = open(fname, O_RDONLY);
+ if (fd < 0) { PFATAL("Unable to open '%s'", fname); }
+
+ u32 read_len = MIN(len, (u32)MAX_FILE);
+ u8 *tmp = ck_alloc(read_len);
+ ck_read(fd, tmp, read_len, fname);
+
+ close(fd);
+
+ char *hex = sha1_hex(tmp, read_len);
+ ck_free(tmp);
+ return hex;
+
+}
+
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index a2c81586..8f685633 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -7,11 +7,11 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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 9c029035..7e875040 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -7,12 +7,12 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com> and
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -111,8 +111,9 @@ 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 ... 7] = 4, [8 ... 15] = 5, [16 ... 31] = 6, [32 ... 127] = 7,
+ [128 ... 255] = 8
};
@@ -177,7 +178,8 @@ fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits;
- const u8 *map = binary_mode ? count_class_binary : count_class_human;
+ const u8 *map = (binary_mode || collect_coverage) ? count_class_binary
+ : count_class_human;
u32 i = map_size;
@@ -239,13 +241,7 @@ static void analyze_results(afl_forkserver_t *fsrv) {
u32 i;
for (i = 0; i < map_size; i++) {
- if (fsrv->trace_bits[i]) {
-
- total += fsrv->trace_bits[i];
- if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i];
- if (!coverage_map[i]) { coverage_map[i] = 1; }
-
- }
+ if (fsrv->trace_bits[i]) { coverage_map[i] |= fsrv->trace_bits[i]; }
}
@@ -328,7 +324,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
if (cmin_mode) {
- fprintf(f, "%u%u\n", fsrv->trace_bits[i], i);
+ fprintf(f, "%u%03u\n", i, fsrv->trace_bits[i]);
} else {
@@ -423,9 +419,9 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
}
- if (fsrv->trace_bits[0] == 1) {
+ if (fsrv->trace_bits[0]) {
- fsrv->trace_bits[0] = 0;
+ fsrv->trace_bits[0] -= 1;
have_coverage = true;
} else {
@@ -654,9 +650,9 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
}
- if (fsrv->trace_bits[0] == 1) {
+ if (fsrv->trace_bits[0]) {
- fsrv->trace_bits[0] = 0;
+ fsrv->trace_bits[0] -= 1;
have_coverage = true;
} else {
@@ -1337,6 +1333,8 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (collect_coverage) { binary_mode = false; } // ensure this
+
if (optind == argc || !out_file) { usage(argv[0]); }
if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
@@ -1609,6 +1607,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (in_dir || in_filelist) {
afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (afl->fsrv.dev_urandom_fd < 0) { PFATAL("Unable to open /dev/urandom"); }
afl->afl_env.afl_custom_mutator_library =
getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
@@ -1674,7 +1673,6 @@ int main(int argc, char **argv_orig, char **envp) {
if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL)
FATAL("coult not grab memory");
edges_only = false;
- raw_instr_output = true;
}
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index e7442d1d..23e0ff13 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -7,12 +7,12 @@
Forkserver design by Jann Horn <jannhorn@googlemail.com>
Now maintained by Marc Heuse <mh@mh-sec.de>,
- Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
+ Heiko Eissfeldt <heiko.eissfeldt@hexco.de> and
Andrea Fioraldi <andreafioraldi@gmail.com> and
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-2023 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2024 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.
@@ -82,6 +82,8 @@ static u8 crash_mode, /* Crash-centric mode? */
remove_shm = 1, /* remove shmem on exit? */
debug; /* debug mode */
+static u32 del_len_limit = 1; /* Minimum block deletion length */
+
static volatile u8 stop_soon; /* Ctrl-C pressed? */
static afl_forkserver_t *fsrv;
@@ -480,7 +482,7 @@ next_del_blksize:
}
- if (del_len > 1 && in_len >= 1) {
+ if (del_len > del_len_limit && in_len >= 1) {
del_len /= 2;
goto next_del_blksize;
@@ -796,8 +798,9 @@ static void usage(u8 *argv0) {
"Minimization settings:\n"
" -e - solve for edge coverage only, ignore hit counts\n"
- " -x - treat non-zero exit codes as crashes\n\n"
- " -H - minimize a hang (hang mode)\n"
+ " -l bytes - set minimum block deletion length to speed up minimization\n"
+ " -x - treat non-zero exit codes as crashes\n"
+ " -H - minimize a hang (hang mode)\n\n"
"For additional tips, please consult %s/README.md.\n\n"
@@ -829,8 +832,9 @@ static void usage(u8 *argv0) {
int main(int argc, char **argv_orig, char **envp) {
- s32 opt;
- u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0;
+ s32 opt;
+ u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0,
+ del_limit_given = 0;
char **use_argv;
char **argv = argv_cpy_dup(argc, argv_orig);
@@ -846,7 +850,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:xeAOQUWXYHh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:o:f:m:t:l:B:xeAOQUWXYHh")) > 0) {
switch (opt) {
@@ -1055,6 +1059,24 @@ int main(int argc, char **argv_orig, char **envp) {
read_bitmap(optarg, mask_bitmap, map_size);
break;
+ case 'l':
+ if (del_limit_given) { FATAL("Multiple -l options not supported"); }
+ del_limit_given = 1;
+
+ if (!optarg) { FATAL("Wrong usage of -l"); }
+
+ if (optarg[0] == '-') { FATAL("Dangerously low value of -l"); }
+
+ del_len_limit = atoi(optarg);
+
+ if (del_len_limit < 1 || del_len_limit > TMIN_MAX_FILE) {
+
+ FATAL("Value of -l out of range between 1 and TMIN_MAX_FILE");
+
+ }
+
+ break;
+
case 'h':
usage(argv[0]);
return -1;
diff --git a/src/hashmap.c b/src/hashmap.c
new file mode 100644
index 00000000..a0a9283c
--- /dev/null
+++ b/src/hashmap.c
@@ -0,0 +1,149 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "types.h"
+#define TABLE_SIZE 10007 // Use a prime number for better distribution
+
+typedef struct HashNode {
+
+ uint64_t key;
+ struct HashNode *next;
+
+} HashNode;
+
+typedef struct HashMap {
+
+ HashNode **table;
+
+} HashMap;
+
+static HashMap *_hashmap;
+
+void hashmap_reset() {
+
+ if (unlikely(!_hashmap)) {
+
+ _hashmap = (HashMap *)malloc(sizeof(HashMap));
+ _hashmap->table = (HashNode **)malloc(sizeof(HashNode *) * TABLE_SIZE);
+ memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
+
+ } else {
+
+ for (int i = 0; i < TABLE_SIZE; i++) {
+
+ HashNode *node = _hashmap->table[i];
+ while (node) {
+
+ HashNode *temp = node;
+ node = node->next;
+ free(temp);
+
+ }
+
+ }
+
+ memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
+
+ }
+
+}
+
+static inline unsigned int hash(uint64_t key) {
+
+ return key % TABLE_SIZE;
+
+}
+
+// type must be below 8
+bool hashmap_search_and_add(uint8_t type, uint64_t key) {
+
+ if (unlikely(type >= 8)) return false;
+ uint64_t val = (key & 0xf8ffffffffffffff) + (type << 56);
+ unsigned int index = hash(val);
+ HashNode *node = _hashmap->table[index];
+ while (node) {
+
+ if (node->key == val) return true;
+ node = node->next;
+
+ }
+
+ // not found so add it
+ node = (HashNode *)malloc(sizeof(HashNode));
+ node->key = val;
+ node->next = _hashmap->table[index];
+ _hashmap->table[index] = node;
+
+ return false;
+
+}
+
+// type must be below 8
+bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) {
+
+ if (unlikely(type >= 8)) return false;
+ uint64_t key_t = 0;
+ memcpy(((char *)key_t) + (7 - type), key, type + 1);
+ return hashmap_search_and_add(type, key_t);
+
+}
+
+/* below is not used */
+
+void hashmap_insert(uint64_t key) {
+
+ unsigned int index = hash(key);
+ HashNode *node = (HashNode *)malloc(sizeof(HashNode));
+ node->key = key;
+ node->next = _hashmap->table[index];
+ _hashmap->table[index] = node;
+
+}
+
+bool hashmap_search(uint64_t key) {
+
+ unsigned int index = hash(key);
+ HashNode *node = _hashmap->table[index];
+ while (node) {
+
+ if (node->key == key) return true;
+ node = node->next;
+
+ }
+
+ return false;
+
+}
+
+void delete(uint64_t key) {
+
+ unsigned int index = hash(key);
+ HashNode *prev = NULL, *node = _hashmap->table[index];
+ while (node) {
+
+ if (node->key == key) {
+
+ if (prev)
+ prev->next = node->next;
+ else
+ _hashmap->table[index] = node->next;
+ free(node);
+ return;
+
+ }
+
+ prev = node;
+ node = node->next;
+
+ }
+
+}
+
+void freeHashMap(HashMap *map) {
+
+ free(_hashmap->table);
+ free(map);
+
+}
+