aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c2
-rw-r--r--src/afl-as.c2
-rw-r--r--src/afl-cc.c3651
-rw-r--r--src/afl-common.c60
-rw-r--r--src/afl-forkserver.c95
-rw-r--r--src/afl-fuzz-bitmap.c31
-rw-r--r--src/afl-fuzz-cmplog.c2
-rw-r--r--src/afl-fuzz-extras.c7
-rw-r--r--src/afl-fuzz-init.c194
-rw-r--r--src/afl-fuzz-mutators.c14
-rw-r--r--src/afl-fuzz-one.c1227
-rw-r--r--src/afl-fuzz-python.c32
-rw-r--r--src/afl-fuzz-queue.c81
-rw-r--r--src/afl-fuzz-redqueen.c611
-rw-r--r--src/afl-fuzz-run.c62
-rw-r--r--src/afl-fuzz-skipdet.c403
-rw-r--r--src/afl-fuzz-state.c35
-rw-r--r--src/afl-fuzz-stats.c162
-rw-r--r--src/afl-fuzz-statsd.c2
-rw-r--r--src/afl-fuzz.c339
-rw-r--r--src/afl-gotcpu.c2
-rw-r--r--src/afl-ld-lto.c14
-rw-r--r--src/afl-performance.c21
-rw-r--r--src/afl-sharedmem.c2
-rw-r--r--src/afl-showmap.c21
-rw-r--r--src/afl-tmin.c2
26 files changed, 4841 insertions, 2233 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index 5b122741..95f32fee 100644
--- a/src/afl-analyze.c
+++ b/src/afl-analyze.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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..09ba75bf 100644
--- a/src/afl-as.c
+++ b/src/afl-as.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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 9e56828c..e9564277 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.
@@ -47,23 +47,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 +79,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 +117,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 +124,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 +149,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;
+
+}
+
+/*
+ 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);
+
+}
+
+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----- **/
/*
- in find_object() we look here:
+ 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;
+
+ }
- 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
+}
+
+/*
+ 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 +388,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 +409,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 +421,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 +464,16 @@ static u8 *find_object(u8 *obj, u8 *argv0) {
*slash = 0;
tmp = alloc_printf("%s/%s", exepath, obj);
- if (!access(tmp, R_OK)) {
-
- 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 (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- if (!access(tmp, R_OK)) {
+ if (!access(tmp, R_OK)) { return tmp; }
- u8 *dir = alloc_printf("%s/../lib/afl/", exepath);
- obj_path = dir;
- return tmp;
-
- }
+ ck_free(tmp);
}
@@ -283,846 +490,789 @@ 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)) {
-
- obj_path = AFL_PATH;
- return tmp;
-
- }
+ if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
-
tmp = alloc_printf("./%s", obj);
- if (debug) DEBUGF("Trying %s\n", tmp);
-
- if (!access(tmp, R_OK)) {
+ if (aflcc->debug) DEBUGF("Trying %s\n", tmp);
- obj_path = ".";
- return tmp;
-
- }
+ if (!access(tmp, R_OK)) { return tmp; }
ck_free(tmp);
- if (debug) DEBUGF("Trying ... giving up\n");
+ if (aflcc->debug) DEBUGF("Trying ... giving up\n");
return NULL;
}
-void parse_fsanitize(char *string) {
-
- char *p, *ptr = string + strlen("-fsanitize=");
- char *new = malloc(strlen(string) + 1);
- char *tmp = malloc(strlen(ptr));
- u32 count = 0, len, ende = 0;
+/*
+ Deduce some info about compiler toolchains in current system,
+ from the building results of AFL++
+*/
+void find_built_deps(aflcc_state_t *aflcc) {
- if (!new || !tmp) { FATAL("could not acquire memory"); }
- strcpy(new, "-fsanitize=");
+ char *ptr = NULL;
- do {
+#if defined(__x86_64__)
+ if ((ptr = find_object(aflcc, "as")) != NULL) {
- p = strchr(ptr, ',');
- if (!p) {
-
- p = ptr + strlen(ptr) + 1;
- ende = 1;
-
- }
-
- len = p - ptr;
- if (len) {
+ #ifndef __APPLE__
+ // on OSX clang masquerades as GCC
+ aflcc->have_gcc = 1;
+ #endif
+ aflcc->have_clang = 1;
+ ck_free(ptr);
- strncpy(tmp, ptr, len);
- tmp[len] = 0;
- // fprintf(stderr, "Found: %s\n", tmp);
- ptr += len + 1;
- if (*tmp) {
+ }
- u32 copy = 1;
- if (!strcmp(tmp, "fuzzer")) {
+#endif
- need_aflpplib = 1;
- copy = 0;
+ if ((ptr = find_object(aflcc, "SanitizerCoveragePCGUARD.so")) != NULL) {
- } else if (!strncmp(tmp, "fuzzer", 6)) {
+ aflcc->have_optimized_pcguard = 1;
+ ck_free(ptr);
- copy = 0;
+ }
- }
+#if (LLVM_MAJOR >= 3)
- if (copy) {
+ if ((ptr = find_object(aflcc, "SanitizerCoverageLTO.so")) != NULL) {
- if (count) { strcat(new, ","); }
- strcat(new, tmp);
- ++count;
+ aflcc->have_lto = 1;
+ ck_free(ptr);
- }
+ }
- }
+ if ((ptr = find_object(aflcc, "cmplog-routines-pass.so")) != NULL) {
- } else {
+ aflcc->have_llvm = 1;
+ ck_free(ptr);
- ptr++; /*fprintf(stderr, "NO!\n"); */
+ }
- }
+#endif
- } while (!ende);
+#ifdef __ANDROID__
+ aflcc->have_llvm = 1;
+#endif
- strcpy(string, new);
- // fprintf(stderr, "string: %s\n", string);
- // fprintf(stderr, "new: %s\n", new);
+ if ((ptr = find_object(aflcc, "afl-gcc-pass.so")) != NULL) {
-}
+ aflcc->have_gcc_plugin = 1;
+ ck_free(ptr);
-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;
+ }
-static void process_params(u32 argc, char **argv) {
+#if !defined(__ANDROID__) && !defined(ANDROID)
+ ptr = find_object(aflcc, "afl-compiler-rt.o");
- if (cc_par_cnt + argc >= 1024) { FATAL("Too many command line parameters"); }
+ if (!ptr) {
- if (lto_mode && argc > 1) {
+ FATAL(
+ "Unable to find 'afl-compiler-rt.o'. Please set the AFL_PATH "
+ "environment variable.");
- u32 idx;
- for (idx = 1; idx < argc; idx++) {
+ }
- if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+ if (aflcc->debug) { DEBUGF("rt=%s\n", ptr); }
- }
+ ck_free(ptr);
+#endif
- }
+}
- // for (u32 x = 0; x < argc; ++x) fprintf(stderr, "[%u] %s\n", x, argv[x]);
+/** compiler_mode & instrument_mode selecting -----BEGIN----- **/
- /* Process the argument list. */
+/* Select compiler_mode by callname, such as "afl-clang-fast", etc. */
+void compiler_mode_by_callname(aflcc_state_t *aflcc) {
- u8 skip_next = 0;
- while (--argc) {
+ if (strncmp(aflcc->callname, "afl-clang-fast", 14) == 0) {
- u8 *cur = *(++argv);
+ /* 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
- if (skip_next) {
+ } else
- skip_next = 0;
- continue;
+#if (LLVM_MAJOR >= 3)
- }
+ if (strncmp(aflcc->callname, "afl-clang-lto", 13) == 0 ||
- if (cur[0] != '-') { non_dash = 1; }
- if (!strncmp(cur, "--afl", 5)) continue;
+ strncmp(aflcc->callname, "afl-lto", 7) == 0) {
- if (lto_mode && !strncmp(cur, "-flto=thin", 10)) {
+ aflcc->compiler_mode = LTO;
- FATAL(
- "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
- "use afl-clang-fast!");
+ } else
- }
+#endif
- 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 (strncmp(aflcc->callname, "afl-gcc-fast", 12) == 0 ||
- continue;
+ strncmp(aflcc->callname, "afl-g++-fast", 12) == 0) {
- }
+ aflcc->compiler_mode = GCC_PLUGIN;
- if (compiler_mode == GCC_PLUGIN && !strcmp(cur, "-pipe")) { continue; }
+ } else if (strncmp(aflcc->callname, "afl-gcc", 7) == 0 ||
- if (!strcmp(cur, "-z") || !strcmp(cur, "-Wl,-z")) {
+ strncmp(aflcc->callname, "afl-g++", 7) == 0) {
- u8 *param = *(argv + 1);
- if (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs")) {
+ aflcc->compiler_mode = GCC;
- skip_next = 1;
- continue;
+ } else if (strcmp(aflcc->callname, "afl-clang") == 0 ||
- }
+ strcmp(aflcc->callname, "afl-clang++") == 0) {
- }
+ aflcc->compiler_mode = CLANG;
- if ((compiler_mode == GCC || compiler_mode == GCC_PLUGIN) &&
- !strncmp(cur, "-stdlib=", 8)) {
+ }
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
+}
- }
+/*
+ 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 (!strncmp(cur, "-fsanitize-coverage-", 20) && strstr(cur, "list=")) {
+ if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
- have_instr_list = 1;
+ aflcc->passthrough = 1;
- }
+ }
- if (!strncmp(cur, "-fsanitize=", strlen("-fsanitize=")) &&
- strchr(cur, ',')) {
+ char *ptr = getenv("AFL_CC_COMPILER");
- parse_fsanitize(cur);
- if (!cur || strlen(cur) <= strlen("-fsanitize=")) { continue; }
+ if (!ptr) { return; }
- } else if ((!strncmp(cur, "-fsanitize=fuzzer-",
+ if (aflcc->compiler_mode) {
- 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)) {
+ if (!be_quiet) {
- if (!be_quiet) { WARNF("Found '%s' - stripping!", cur); }
- continue;
+ WARNF(
+ "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
+ "selected by command line parameter or symlink, ignoring the "
+ "environment variable!");
}
- if (need_aflpplib || !strcmp(cur, "-fsanitize=fuzzer")) {
+ } else {
- u8 *afllib = find_object("libAFLDriver.a", argv[0]);
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
- if (!be_quiet) {
+ aflcc->compiler_mode = LTO;
- OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
- }
+ aflcc->compiler_mode = LLVM;
- if (!afllib) {
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
- if (!be_quiet) {
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
- WARNF(
- "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
- "the flags - this will fail!");
+ aflcc->compiler_mode = GCC_PLUGIN;
- }
+ } else if (strcasecmp(ptr, "GCC") == 0) {
- } else {
+ aflcc->compiler_mode = GCC;
- cc_params[cc_par_cnt++] = afllib;
+ } else if (strcasecmp(ptr, "CLANG") == 0) {
-#ifdef __APPLE__
- cc_params[cc_par_cnt++] = "-undefined";
- cc_params[cc_par_cnt++] = "dynamic_lookup";
-#endif
+ aflcc->compiler_mode = CLANG;
- }
+ } else
- if (need_aflpplib) {
+ FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
- need_aflpplib = 0;
+ }
- } else {
+}
- continue;
+/*
+ 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 (!strcmp(cur, "-m32")) bit_mode = 32;
- if (!strcmp(cur, "armv7a-linux-androideabi")) bit_mode = 32;
- if (!strcmp(cur, "-m64")) bit_mode = 64;
+ if (strncmp(argv[i], "--afl", 5) == 0) {
- if (!strcmp(cur, "-fsanitize=address") || !strcmp(cur, "-fsanitize=memory"))
- asan_set = 1;
+ if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
- if (strstr(cur, "FORTIFY_SOURCE")) fortify_set = 1;
+ aflcc->passthrough = 1;
+ argv[i] = "-g"; // we have to overwrite it, -g is always good
+ continue;
- 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;
+ }
- if (!strncmp(cur, "-O", 2)) have_o = 1;
- if (!strncmp(cur, "-funroll-loop", 13)) have_unroll = 1;
+ if (aflcc->compiler_mode && !be_quiet) {
- if (*cur == '@') {
+ WARNF(
+ "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
+ "symlink compiler selection!");
- // 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) {
+ ptr = argv[i];
+ ptr += 5;
+ while (*ptr == '-')
+ ptr++;
- cc_params[cc_par_cnt++] = cur;
- continue;
+ if (strncasecmp(ptr, "LTO", 3) == 0) {
- }
+ aflcc->compiler_mode = LTO;
- u8 *tmpbuf = malloc(st.st_size + 2), *ptr;
- char **args = malloc(sizeof(char *) * (st.st_size >> 1));
- int count = 1, cont = 0, cont_act = 0;
+ } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
- while (fgets(tmpbuf, st.st_size + 1, f)) {
+ aflcc->compiler_mode = LLVM;
- ptr = tmpbuf;
- // fprintf(stderr, "1: %s\n", ptr);
- // no leading whitespace
- while (isspace(*ptr)) {
+ } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
- ++ptr;
- cont_act = 0;
+ strncasecmp(ptr, "PC-GUARD", 8) == 0) {
- }
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
- // 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] == '\\') {
+ } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
- cont = 1;
- ptr[strlen(ptr) - 1] = 0;
+ strcasecmp(ptr, "CFG") == 0) {
- }
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
- // fprintf(stderr, "2: %s\n", ptr);
+ } else if (strcasecmp(ptr, "AFL") == 0 ||
- // remove whitespace at end
- while (*ptr && isspace(ptr[strlen(ptr) - 1])) {
+ strcasecmp(ptr, "CLASSIC") == 0) {
- ptr[strlen(ptr) - 1] = 0;
- cont = 0;
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
- }
+ } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
- // fprintf(stderr, "3: %s\n", ptr);
- if (*ptr) {
+ strcasecmp(ptr, "NATIVE") == 0 ||
+ strcasecmp(ptr, "LLVM-NATIVE") == 0) {
- do {
+ aflcc->compiler_mode = LLVM;
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- u8 *value = ptr;
- while (*ptr && !isspace(*ptr)) {
+ } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
- ++ptr;
+ strncasecmp(ptr, "GCC-P", 5) == 0 ||
+ strncasecmp(ptr, "GCCP", 4) == 0) {
- }
+ aflcc->compiler_mode = GCC_PLUGIN;
- while (*ptr && isspace(*ptr)) {
+ } else if (strcasecmp(ptr, "GCC") == 0) {
- *ptr++ = 0;
+ aflcc->compiler_mode = GCC;
- }
+ } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
- if (cont_act) {
+ aflcc->compiler_mode = CLANG;
- 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;
+ } else
- } else {
+ FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
- args[count++] = strdup(value);
+ }
- }
+ }
- } while (*ptr);
+}
- }
+/*
+ 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 (cont) {
+ if (getenv("AFL_LLVM_INSTRIM") || getenv("INSTRIM") ||
+ getenv("INSTRIM_LIB")) {
- cont_act = 1;
- cont = 0;
+ 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 (count) { process_params(count, args); }
+ 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");
- // we cannot free args[]
- free(tmpbuf);
+ }
- continue;
+ if (getenv("AFL_LLVM_CTX")) aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ if (getenv("AFL_LLVM_CALLER"))
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- }
+ if (getenv("AFL_LLVM_NGRAM_SIZE")) {
- cc_params[cc_par_cnt++] = cur;
+ 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 (getenv("AFL_LLVM_CTX_K")) {
-/* Copy argv to cc_params, making the necessary edits. */
+ 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) {
-static void edit_params(u32 argc, char **argv, char **envp) {
+ setenv("AFL_LLVM_CALLER", "1", 1);
+ unsetenv("AFL_LLVM_CTX_K");
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- cc_params = ck_alloc(1024 * sizeof(u8 *));
+ } else {
- if (lto_mode) {
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
- if (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;
+ }
}
- if (plusplus_mode) {
+}
- u8 *alt_cxx = getenv("AFL_CXX");
+/*
+ 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) {
- if (!alt_cxx) {
+ if (!getenv("AFL_LLVM_INSTRUMENT")) { return; }
- if (compiler_mode >= GCC_PLUGIN) {
+ u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
- if (compiler_mode == GCC) {
+ while (ptr2) {
- alt_cxx = clang_mode ? "clang++" : "g++";
+ if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
+ strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
- } else if (compiler_mode == CLANG) {
+ if (aflcc->instrument_mode == INSTRUMENT_LTO) {
- alt_cxx = "clang++";
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
+ aflcc->lto_mode = 1;
- } else {
+ } else if (!aflcc->instrument_mode ||
- alt_cxx = "g++";
+ aflcc->instrument_mode == INSTRUMENT_AFL) {
- }
+ aflcc->instrument_mode = INSTRUMENT_AFL;
} else {
- if (USE_BINDIR)
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++",
- LLVM_BINDIR);
- else
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN);
- alt_cxx = llvm_fullpath;
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
}
- cc_params[0] = alt_cxx;
+ if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
+ strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
- } else {
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_PCGUARD)
- u8 *alt_cc = getenv("AFL_CC");
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
- if (!alt_cc) {
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
- if (compiler_mode >= GCC_PLUGIN) {
+ }
- if (compiler_mode == GCC) {
+ if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
+ strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
+ strncasecmp(ptr2, "native", strlen("native")) == 0) {
- alt_cc = clang_mode ? "clang" : "gcc";
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE)
- } else if (compiler_mode == CLANG) {
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- alt_cc = "clang";
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
- } else {
+ }
- alt_cc = "gcc";
+ if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
+ strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
- }
+ if (!aflcc->instrument_mode ||
+ aflcc->instrument_mode == INSTRUMENT_LLVMNATIVE) {
+
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
} else {
- if (USE_BINDIR)
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
- LLVM_BINDIR);
- else
- snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s", CLANG_BIN);
- alt_cc = llvm_fullpath;
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
}
- cc_params[0] = alt_cc;
+ if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
+ strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
- }
+ FATAL(
+ "InsTrim instrumentation was removed. Use a modern LLVM and "
+ "PCGUARD (default in afl-cc).\n");
+
+ }
- if (compiler_mode == GCC || compiler_mode == CLANG) {
+ if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
- cc_params[cc_par_cnt++] = "-B";
- cc_params[cc_par_cnt++] = obj_path;
+ aflcc->lto_mode = 1;
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_LTO)
- if (clang_mode || compiler_mode == CLANG) {
+ aflcc->instrument_mode = INSTRUMENT_LTO;
- cc_params[cc_par_cnt++] = "-no-integrated-as";
+ else
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
}
- }
+ if (strcasecmp(ptr2, "gcc") == 0) {
- if (compiler_mode == GCC_PLUGIN) {
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_GCC)
- char *fplugin_arg;
+ aflcc->instrument_mode = INSTRUMENT_GCC;
- if (cmplog_mode) {
+ else if (aflcc->instrument_mode != INSTRUMENT_GCC)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_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;
+ aflcc->compiler_mode = GCC;
}
- 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";
-
- }
+ if (strcasecmp(ptr2, "clang") == 0) {
- if (compiler_mode == LLVM || compiler_mode == LTO) {
+ if (!aflcc->instrument_mode || aflcc->instrument_mode == INSTRUMENT_CLANG)
- cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+ aflcc->instrument_mode = INSTRUMENT_CLANG;
- if (lto_mode && have_instr_env) {
+ else if (aflcc->instrument_mode != INSTRUMENT_CLANG)
+ FATAL("main instrumentation mode already set with %s",
+ instrument_mode_2str(aflcc->instrument_mode));
-#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
+ aflcc->compiler_mode = CLANG;
}
- if (getenv("AFL_LLVM_DICT2FILE")) {
+ if (strncasecmp(ptr2, "ctx-", strlen("ctx-")) == 0 ||
+ strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
+ strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
-#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
+ u8 *ptr3 = ptr2;
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
+ ptr3++;
- }
+ if (!*ptr3) {
- // laf
- if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) {
+ 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");
-#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
+ }
+
+ 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 {
+
+ aflcc->instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
+ u8 *ptr4 = alloc_printf("%u", aflcc->ctx_k);
+ setenv("AFL_LLVM_CTX_K", ptr4, 1);
+
+ }
}
- if (getenv("LAF_TRANSFORM_COMPARES") ||
- getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) {
+ if (strcasecmp(ptr2, "ctx") == 0) {
-#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);
-#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
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CTX;
+ setenv("AFL_LLVM_CTX", "1", 1);
}
- if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") ||
- getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) {
+ if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
-#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
+ aflcc->instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ setenv("AFL_LLVM_CALLER", "1", 1);
}
- // /laf
+ if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
- unsetenv("AFL_LD");
- unsetenv("AFL_LD_CALLER");
+ u8 *ptr3 = ptr2 + strlen("ngram");
+ while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9')) {
- if (cmplog_mode) {
+ ptr3++;
- 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);
+ if (!*ptr3) {
- // 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
+ 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");
+
+ }
+
+ 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 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
+ ptr2 = strtok(NULL, ":,;");
- if (lto_mode && !have_c) {
+ }
- u8 *ld_path = NULL;
- if (getenv("AFL_REAL_LD")) {
+}
- ld_path = strdup(getenv("AFL_REAL_LD"));
+/*
+ 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) {
- } else {
+ if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
+ getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
+ getenv("AFL_LLVM_BLOCKLIST")) {
- ld_path = strdup(AFL_REAL_LD);
+ aflcc->have_instr_env = 1;
- }
+ }
- if (!ld_path || !*ld_path) {
+ if (aflcc->have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
- if (ld_path) {
+ WARNF(
+ "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
+ "for file matching, only function matching!");
- // Freeing empty string
- free(ld_path);
+ }
- }
+ instrument_mode_old_environ(aflcc);
+ instrument_mode_new_environ(aflcc);
- ld_path = strdup("ld.lld");
+}
- }
+/*
+ Workaround to ensure CALLER, CTX, K-CTX and NGRAM
+ instrumentation were used correctly.
+*/
+static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
- 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);
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
-#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
+ FATAL("you cannot set CTX and CALLER together");
- cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition";
- cc_params[cc_par_cnt++] = lto_flag;
+ }
- } else {
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
- if (instrument_mode == INSTRUMENT_PCGUARD) {
+ FATAL("you cannot set CTX and K-CTX together");
-#if LLVM_MAJOR >= 13
- #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 >= 13 /* 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
+ }
- }
+ if ((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
+ (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
- #endif
-#else
- #if LLVM_MAJOR >= 4
- if (!be_quiet)
- SAYF(
- "Using unoptimized trace-pc-guard, upgrade to LLVM 13+ 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
+ FATAL("you cannot set CALLER and K-CTX together");
- } else if (instrument_mode == INSTRUMENT_LLVMNATIVE) {
+ }
-#if LLVM_MAJOR >= 4
- if (instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
+ if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM)
+ FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
- #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
+ if (aflcc->instrument_opt_mode &&
+ aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
+ aflcc->instrument_mode != INSTRUMENT_CLASSIC)
+ FATAL(
+ "CALLER, CTX and NGRAM instrumentation options can only be used with "
+ "the LLVM CLASSIC instrumentation mode.");
- } else {
+}
- cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard";
+/*
+ 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) {
- }
+ if (aflcc->instrument_opt_mode &&
+ aflcc->instrument_mode == INSTRUMENT_DEFAULT &&
+ (aflcc->compiler_mode == LLVM || aflcc->compiler_mode == UNSET)) {
-#else
- FATAL("pcguard instrumentation requires LLVM 4.0.1+");
-#endif
+ aflcc->instrument_mode = INSTRUMENT_CLASSIC;
+ aflcc->compiler_mode = LLVM;
- } 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/afl-llvm-pass.so", obj_path);
-#else
+ if (!aflcc->compiler_mode) {
- 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
+ // 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");
- }
+ }
- }
+ switch (aflcc->compiler_mode) {
- if (cmplog_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");
-#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
+ }
+
+ if (aflcc->compiler_mode == GCC) { aflcc->instrument_mode = INSTRUMENT_GCC; }
+
+ if (aflcc->compiler_mode == CLANG) {
+
+ /* 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)) {
+
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
+
+ } else {
+
+ aflcc->instrument_mode = INSTRUMENT_CLANG;
+ setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as
}
- // cc_params[cc_par_cnt++] = "-Qunused-arguments";
+ }
+
+ if (aflcc->compiler_mode == LTO) {
- if (lto_mode && argc > 1) {
+ if (aflcc->instrument_mode == 0 ||
+ aflcc->instrument_mode == INSTRUMENT_LTO ||
+ aflcc->instrument_mode == INSTRUMENT_CFG ||
+ aflcc->instrument_mode == INSTRUMENT_PCGUARD) {
- u32 idx;
- for (idx = 1; idx < argc; idx++) {
+ aflcc->lto_mode = 1;
+ // force CFG
+ // if (!aflcc->instrument_mode) {
+
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+ // }
+
+ } else if (aflcc->instrument_mode == INSTRUMENT_CLASSIC) {
+
+ aflcc->lto_mode = 1;
- if (!strncasecmp(argv[idx], "-fpic", 5)) have_pic = 1;
+ } else {
+
+ if (!be_quiet) {
+
+ WARNF("afl-clang-lto called with mode %s, using that mode instead",
+ instrument_mode_2str(aflcc->instrument_mode));
}
@@ -1130,958 +1280,1420 @@ static void edit_params(u32 argc, char **argv, char **envp) {
}
- /* Inspect the command line parameters. */
+ if (aflcc->instrument_mode == 0 && aflcc->compiler_mode < GCC_PLUGIN) {
- process_params(argc, argv);
+#if LLVM_MAJOR >= 7
+ #if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
+ if (aflcc->have_instr_env) {
- if (!have_pic) { cc_params[cc_par_cnt++] = "-fPIC"; }
+ aflcc->instrument_mode = INSTRUMENT_AFL;
+ if (!be_quiet) {
- // 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)) {
+ WARNF(
+ "Switching to classic instrumentation because "
+ "AFL_LLVM_ALLOWLIST/DENYLIST does not work with PCGUARD < 10.0.1.");
- cc_params[cc_par_cnt++] = "-Wl,-rpath";
- cc_params[cc_par_cnt++] = libdir;
+ }
- } else {
+ } else
- free(libdir);
+ #endif
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+#else
+ aflcc->instrument_mode = INSTRUMENT_AFL;
+#endif
}
- if (getenv("AFL_HARDEN")) {
+ if (!aflcc->instrument_opt_mode && aflcc->lto_mode &&
+ aflcc->instrument_mode == INSTRUMENT_CFG) {
+
+ aflcc->instrument_mode = INSTRUMENT_PCGUARD;
+
+ }
+
+#ifndef AFL_CLANG_FLTO
+ if (aflcc->lto_mode)
+ FATAL(
+ "instrumentation mode LTO specified but LLVM support not available "
+ "(requires LLVM 11 or higher)");
+#endif
- cc_params[cc_par_cnt++] = "-fstack-protector-all";
+ if (aflcc->lto_mode) {
- if (!fortify_set) cc_params[cc_par_cnt++] = "-D_FORTIFY_SOURCE=2";
+ if (aflcc->lto_flag[0] != '-')
+ FATAL(
+ "Using afl-clang-lto is not possible because Makefile magic did not "
+ "identify the correct -flto flag");
+ else
+ aflcc->compiler_mode = LTO;
}
- if (!asan_set) {
+ 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 (getenv("AFL_USE_ASAN")) {
+#if LLVM_MAJOR < 11 && (LLVM_MAJOR < 10 || LLVM_MINOR < 1)
- if (getenv("AFL_USE_MSAN")) FATAL("ASAN and MSAN are mutually exclusive");
+ if (aflcc->instrument_mode == INSTRUMENT_PCGUARD && aflcc->have_instr_env) {
- if (getenv("AFL_HARDEN"))
- FATAL("ASAN and AFL_HARDEN are mutually exclusive");
+ FATAL(
+ "Instrumentation type PCGUARD does not support "
+ "AFL_LLVM_ALLOWLIST/DENYLIST! Use LLVM 10.0.1+ instead.");
- cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
- cc_params[cc_par_cnt++] = "-fsanitize=address";
+ }
- } else if (getenv("AFL_USE_MSAN")) {
+#endif
- if (getenv("AFL_USE_ASAN")) FATAL("ASAN and MSAN are mutually exclusive");
+ instrument_opt_mode_exclude(aflcc);
- if (getenv("AFL_HARDEN"))
- FATAL("MSAN and AFL_HARDEN are mutually exclusive");
+ u8 *ptr2;
- cc_params[cc_par_cnt++] = "-U_FORTIFY_SOURCE";
- cc_params[cc_par_cnt++] = "-fsanitize=memory";
+ if ((ptr2 = getenv("AFL_LLVM_DICT2FILE")) != NULL && *ptr2 != '/')
+ FATAL("AFL_LLVM_DICT2FILE must be set to an absolute file path");
- }
+ if (getenv("AFL_LLVM_LAF_ALL")) {
+
+ 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_USE_UBSAN")) {
+ aflcc->cmplog_mode = getenv("AFL_CMPLOG") || getenv("AFL_LLVM_CMPLOG") ||
+ getenv("AFL_GCC_CMPLOG");
+
+}
- 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";
+/*
+ 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 : "");
- if (getenv("AFL_USE_TSAN")) {
+ ck_free(ptr2);
+ ck_free(ptr3);
- cc_params[cc_par_cnt++] = "-fsanitize=thread";
- cc_params[cc_par_cnt++] = "-fno-omit-frame-pointer";
+ 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);
}
- if (getenv("AFL_USE_LSAN")) {
+ ck_free(ptr1);
- 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 (!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!");
}
- if (getenv("AFL_USE_CFISAN")) {
+}
- if (compiler_mode == GCC_PLUGIN || compiler_mode == GCC) {
+/*
+ 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) {
- cc_params[cc_par_cnt++] = "-fcf-protection=full";
+ static u8 llvm_fullpath[PATH_MAX];
- } else {
+ if (aflcc->plusplus_mode) {
- if (!lto_mode) {
+ u8 *alt_cxx = getenv("AFL_CXX");
- 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 (!alt_cxx) {
- }
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
- cc_params[cc_par_cnt++] = "-fsanitize=cfi";
- cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+ alt_cxx = "g++";
- }
+ } else if (aflcc->compiler_mode == CLANG) {
- }
+ alt_cxx = "clang++";
- if (!getenv("AFL_DONT_OPTIMIZE")) {
+ } else {
- 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;
+ if (USE_BINDIR)
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++",
+ LLVM_BINDIR);
+ else
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANGPP_BIN);
+ alt_cxx = llvm_fullpath;
- }
+ }
- if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
- getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_ALL") ||
- lto_mode) {
+ }
- 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";
+ aflcc->cc_params[0] = alt_cxx;
- }
+ } else {
-#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
- if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
-#endif
+ u8 *alt_cc = getenv("AFL_CC");
+
+ if (!alt_cc) {
- cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
- cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == GCC_PLUGIN) {
- /* 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) {
+ alt_cc = "gcc";
- cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
+ } else if (aflcc->compiler_mode == CLANG) {
- /* 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:
+ alt_cc = "clang";
- 1) We need to convince the compiler not to optimize out the signature.
- This is done with __attribute__((used)).
+ } else {
- 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.
+ if (USE_BINDIR)
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang",
+ LLVM_BINDIR);
+ else
+ snprintf(llvm_fullpath, sizeof(llvm_fullpath), CLANG_BIN);
+ alt_cc = llvm_fullpath;
- 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.
+ }
- */
+ }
- 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;";
+ aflcc->cc_params[0] = alt_cc;
}
- if (plusplus_mode) {
+}
+
+/** compiler_mode & instrument_mode selecting -----END----- **/
+
+/** Macro defs for the preprocessor -----BEGIN----- **/
+
+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");
+
+}
+
+/*
+ __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 (aflcc->plusplus_mode) {
- 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();";
+ 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 {
- 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();";
+ 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();");
}
- cc_params[cc_par_cnt++] =
+ insert_param(
+ aflcc,
"-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)";
+ "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()");
+
+}
+
+/*
+ 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 (compiler_mode != GCC && compiler_mode != CLANG) {
+ if (aflcc->compiler_mode == GCC || aflcc->compiler_mode == CLANG) return;
- 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;"
+ insert_param(aflcc, "-D__AFL_HAVE_MANUAL_CONTROL=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)).
+
+ 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.
+
+ */
+
+ insert_param(aflcc,
+ "-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,
+ "-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : "
+ "__afl_fuzz_alt_ptr)");
+
+ 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\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
#else
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"__afl_persistent_loop\"); "
+ "__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
- "\"; "
+ // 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\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"___afl_manual_init\"); "
#else
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"__afl_manual_init\"); "
+ "__attribute__((visibility(\"default\"))) "
+ "void _I(void) __asm__(\"__afl_manual_init\"); "
#endif /* ^__APPLE__ */
- "_I(); } while (0)";
+ "_I(); } while (0)");
- }
+}
- if (x_set) {
+/*
+ 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) {
- cc_params[cc_par_cnt++] = "-x";
- cc_params[cc_par_cnt++] = "none";
+ if (aflcc->have_fortify) { return; }
- }
+ switch (action) {
- // prevent unnecessary build errors
- if (compiler_mode != GCC_PLUGIN && compiler_mode != GCC) {
+ case 1:
+ insert_param(aflcc, "-D_FORTIFY_SOURCE=1");
+ break;
- cc_params[cc_par_cnt++] = "-Wno-unused-command-line-argument";
+ case 2:
+ insert_param(aflcc, "-D_FORTIFY_SOURCE=2");
+ break;
+
+ default: // OFF
+ insert_param(aflcc, "-U_FORTIFY_SOURCE");
+ break;
}
- if (preprocessor_only || have_c || !non_dash) {
+ aflcc->have_fortify = 1;
- /* 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;
+}
- }
+/* Macro defs of __AFL_LEAK_CHECK, __AFL_LSAN_ON and __AFL_LSAN_OFF */
+void add_defs_lsan_ctrl(aflcc_state_t *aflcc) {
-#ifndef __ANDROID__
+ 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 (compiler_mode != GCC && compiler_mode != CLANG) {
+}
- switch (bit_mode) {
+/** Macro defs for the preprocessor -----END----- **/
- 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;
+/** About -fsanitize -----BEGIN----- **/
- case 32:
- if (!shared_linking && !partial_linking) {
+/* For input "-fsanitize=...", it:
- 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");
+ 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 (lto_mode) {
+ 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;
- 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");
+ strcpy(new, "-fsanitize=");
- }
+ do {
- break;
+ p = strchr(ptr, ',');
+ if (!p) {
- case 64:
- if (!shared_linking && !partial_linking) {
+ p = ptr + strlen(ptr) + 1;
+ ende = 1;
- 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");
+ }
+
+ len = p - ptr;
+ if (len) {
+
+ strncpy(tmp, ptr, len);
+ tmp[len] = 0;
+ // fprintf(stderr, "Found: %s\n", tmp);
+ ptr += len + 1;
+ if (*tmp) {
+
+ u32 copy = 1;
+ if (!strcmp(tmp, "fuzzer")) {
+
+ detect_single_fuzzer = 1;
+ copy = 0;
+
+ } else if (!strncmp(tmp, "fuzzer", 6)) {
+
+ copy = 0;
}
- if (lto_mode) {
+ if (copy) {
- 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");
+ if (count) { strcat(new, ","); }
+ strcat(new, tmp);
+ ++count;
}
- break;
+ }
+
+ } else {
+
+ ptr++;
}
- #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
+ } while (!ende);
- #if defined(__APPLE__)
- if (shared_linking || partial_linking) {
+ strcpy(string, new);
- 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";
+ ck_free(tmp);
+ ck_free(new);
- }
+ return detect_single_fuzzer;
- #endif
+}
+
+/*
+ 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 defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
- cc_params[cc_par_cnt++] = "-lrt";
- #endif
+#undef HAVE_SANITIZER_SCAN_KEEP
-#endif
+ // 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")) {
- cc_params[cc_par_cnt] = NULL;
+ if (scan) {
-}
+ aflcc->need_aflpplib = 1;
+ final_ = PARAM_SCAN;
-/* Main entry point */
+ } else {
-int main(int argc, char **argv, char **envp) {
+ final_ = PARAM_DROP;
- int i;
- char *callname = argv[0], *ptr = NULL;
+ }
- if (getenv("AFL_DEBUG")) {
+ } else if (!strncmp(cur_argv, "-fsanitize=", strlen("-fsanitize=")) &&
- debug = 1;
- if (strcmp(getenv("AFL_DEBUG"), "0") == 0) unsetenv("AFL_DEBUG");
+ strchr(cur_argv, ',') &&
+ !strstr(cur_argv, "=,")) { // avoid OOB errors
- } else if (getenv("AFL_QUIET"))
+ if (scan) {
- be_quiet = 1;
+ u8 *cur_argv_ = ck_strdup(cur_argv);
- if (getenv("AFL_LLVM_INSTRUMENT_FILE") || getenv("AFL_LLVM_WHITELIST") ||
- getenv("AFL_LLVM_ALLOWLIST") || getenv("AFL_LLVM_DENYLIST") ||
- getenv("AFL_LLVM_BLOCKLIST")) {
+ if (fsanitize_fuzzer_comma(cur_argv_)) {
+
+ aflcc->need_aflpplib = 1;
+ final_ = PARAM_SCAN;
+
+ }
+
+ ck_free(cur_argv_);
- have_instr_env = 1;
+ } else {
+
+ fsanitize_fuzzer_comma(cur_argv);
+ if (!cur_argv || strlen(cur_argv) <= strlen("-fsanitize="))
+ final_ = PARAM_DROP; // this means it only has "fuzzer" previously.
+
+ }
+
+ } else if (!strncmp(cur_argv, "-fsanitize-coverage-", 20) &&
+
+ strstr(cur_argv, "list=")) {
+
+ if (scan) {
+
+ aflcc->have_instr_list = 1;
+ final_ = PARAM_SCAN;
+
+ } else {
+
+ if (aflcc->instrument_mode != INSTRUMENT_LLVMNATIVE) {
+
+ if (!be_quiet) { WARNF("Found '%s' - stripping!", cur_argv); }
+ final_ = PARAM_DROP;
+
+ } else {
+
+ final_ = PARAM_KEEP;
+
+ }
+
+ }
}
- if (getenv("AFL_PASSTHROUGH") || getenv("AFL_NOOPT")) {
+ if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
- passthrough = 1;
- if (!debug) { be_quiet = 1; }
+ return final_;
+
+}
+
+/*
+ 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) {
+
+ if (getenv("AFL_USE_ASAN") || aflcc->have_asan) {
+
+ if (getenv("AFL_USE_MSAN") || aflcc->have_msan)
+ FATAL("ASAN and MSAN are mutually exclusive");
+
+ if (getenv("AFL_HARDEN"))
+ FATAL("ASAN and AFL_HARDEN are mutually exclusive");
+
+ if (aflcc->compiler_mode == GCC_PLUGIN && !aflcc->have_staticasan) {
+
+ insert_param(aflcc, "-static-libasan");
+
+ }
+
+ add_defs_fortify(aflcc, 0);
+ if (!aflcc->have_asan) { insert_param(aflcc, "-fsanitize=address"); }
+ 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_HARDEN"))
+ FATAL("MSAN and AFL_HARDEN are mutually exclusive");
+
+ add_defs_fortify(aflcc, 0);
+ if (!aflcc->have_msan) { insert_param(aflcc, "-fsanitize=memory"); }
+ aflcc->have_msan = 1;
}
- if ((ptr = strrchr(callname, '/')) != NULL) callname = ptr + 1;
- argvnull = (u8 *)argv[0];
- check_environment_vars(envp);
+ if (getenv("AFL_USE_UBSAN") || aflcc->have_ubsan) {
- if ((ptr = find_object("as", argv[0])) != NULL) {
+ if (!aflcc->have_ubsan) {
- have_gcc = 1;
- ck_free(ptr);
+ insert_param(aflcc, "-fsanitize=undefined");
+ insert_param(aflcc, "-fsanitize-undefined-trap-on-error");
+ insert_param(aflcc, "-fno-sanitize-recover=all");
+
+ }
+
+ if (!aflcc->have_fp) {
+
+ insert_param(aflcc, "-fno-omit-frame-pointer");
+ aflcc->have_fp = 1;
+
+ }
+
+ aflcc->have_ubsan = 1;
}
-#if (LLVM_MAJOR >= 3)
+ if (getenv("AFL_USE_TSAN") || aflcc->have_tsan) {
- if ((ptr = find_object("SanitizerCoverageLTO.so", argv[0])) != NULL) {
+ if (!aflcc->have_fp) {
- have_lto = 1;
- ck_free(ptr);
+ 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 ((ptr = find_object("cmplog-routines-pass.so", argv[0])) != NULL) {
+ if (getenv("AFL_USE_LSAN") && !aflcc->have_lsan) {
- have_llvm = 1;
- ck_free(ptr);
+ insert_param(aflcc, "-fsanitize=leak");
+ add_defs_lsan_ctrl(aflcc);
+ aflcc->have_lsan = 1;
}
-#endif
+ if (getenv("AFL_USE_CFISAN") || aflcc->have_cfisan) {
-#ifdef __ANDROID__
- have_llvm = 1;
-#endif
+ if (aflcc->compiler_mode == GCC_PLUGIN || aflcc->compiler_mode == GCC) {
- if ((ptr = find_object("afl-gcc-pass.so", argv[0])) != NULL) {
+ if (!aflcc->have_fcf) { insert_param(aflcc, "-fcf-protection=full"); }
- have_gcc_plugin = 1;
- ck_free(ptr);
+ } else {
+
+ if (!aflcc->lto_mode && !aflcc->have_flto) {
+
+ uint32_t i = 0, found = 0;
+ while (envp[i] != NULL && !found) {
+
+ if (strncmp("-flto", envp[i++], 5) == 0) found = 1;
+
+ }
+
+ if (!found) { insert_param(aflcc, "-flto"); }
+ aflcc->have_flto = 1;
+
+ }
+
+ if (!aflcc->have_cfisan) { insert_param(aflcc, "-fsanitize=cfi"); }
+
+ if (!aflcc->have_hidden) {
+
+ insert_param(aflcc, "-fvisibility=hidden");
+ aflcc->have_hidden = 1;
+
+ }
+
+ aflcc->have_cfisan = 1;
+
+ }
}
-#if (LLVM_MAJOR >= 3)
+}
- if (strncmp(callname, "afl-clang-fast", 14) == 0) {
+/* Add params to enable LLVM SanCov, the native PCGUARD */
+void add_native_pcguard(aflcc_state_t *aflcc) {
- compiler_mode = LLVM;
+ /* 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; }
- } else if (strncmp(callname, "afl-clang-lto", 13) == 0 ||
+ /* If llvm-config doesn't figure out LLVM_MAJOR, just
+ go on anyway and let compiler complain if doesn't work. */
- strncmp(callname, "afl-lto", 7) == 0) {
+#if LLVM_MAJOR > 0 && LLVM_MAJOR < 6
+ FATAL("pcguard instrumentation with pc-table requires LLVM 6.0.1+");
+#else
+ #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) {
- compiler_mode = LTO;
+ insert_param(aflcc,
+ "-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
- } else
+ } else {
+
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard,pc-table");
+
+ }
#endif
- if (strncmp(callname, "afl-gcc-fast", 12) == 0 ||
- strncmp(callname, "afl-g++-fast", 12) == 0) {
+}
+
+/*
+ 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 LLVM_MAJOR >= 13
+ #if defined __ANDROID__ || ANDROID
- compiler_mode = GCC_PLUGIN;
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- } else if (strncmp(callname, "afl-gcc", 7) == 0 ||
+ #else
- strncmp(callname, "afl-g++", 7) == 0) {
+ if (aflcc->have_instr_list) {
- compiler_mode = GCC;
+ 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");
- } else if (strcmp(callname, "afl-clang") == 0 ||
+ insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
+ aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
- strcmp(callname, "afl-clang++") == 0) {
+ } else {
- compiler_mode = CLANG;
+ /* 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);
}
- if ((ptr = getenv("AFL_CC_COMPILER"))) {
+ #endif // defined __ANDROID__ || ANDROID
+#else // LLVM_MAJOR < 13
+ #if LLVM_MAJOR >= 4
- if (compiler_mode) {
+ 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 (!be_quiet) {
+ #else
- WARNF(
- "\"AFL_CC_COMPILER\" is set but a specific compiler was already "
- "selected by command line parameter or symlink, ignoring the "
- "environment variable!");
+ FATAL("pcguard instrumentation requires LLVM 4.0.1+");
- }
+ #endif
+#endif
+
+}
+
+/** About -fsanitize -----END----- **/
+
+/** 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 (aflcc->lto_mode && !strncmp(cur_argv, "-flto=thin", 10)) {
+
+ FATAL(
+ "afl-clang-lto cannot work with -flto=thin. Switch to -flto=full or "
+ "use afl-clang-fast!");
+
+ }
+
+ param_st final_ = PARAM_MISS;
+
+ if (!strcmp(cur_argv, "-shared") || !strcmp(cur_argv, "-dynamiclib")) {
+
+ if (scan) {
+
+ aflcc->shared_linking = 1;
+ final_ = PARAM_SCAN;
} else {
- if (strncasecmp(ptr, "LTO", 3) == 0) {
+ final_ = PARAM_KEEP;
- compiler_mode = LTO;
+ }
- } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+ } else if (!strcmp(cur_argv, "-Wl,-r") || !strcmp(cur_argv, "-Wl,-i") ||
- compiler_mode = LLVM;
+ !strcmp(cur_argv, "-Wl,--relocatable") ||
+ !strcmp(cur_argv, "-r") || !strcmp(cur_argv, "--relocatable")) {
- } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+ if (scan) {
- strncasecmp(ptr, "GCC-P", 5) == 0 ||
- strncasecmp(ptr, "GCCP", 4) == 0) {
+ aflcc->partial_linking = 1;
+ final_ = PARAM_SCAN;
- compiler_mode = GCC_PLUGIN;
+ } else {
- } else if (strcasecmp(ptr, "GCC") == 0) {
+ final_ = PARAM_KEEP;
- compiler_mode = GCC;
+ }
- } else
+ } else if (!strncmp(cur_argv, "-fuse-ld=", 9) ||
+
+ !strncmp(cur_argv, "--ld-path=", 10)) {
+
+ if (scan) {
- FATAL("Unknown AFL_CC_COMPILER mode: %s\n", ptr);
+ final_ = PARAM_SCAN;
+
+ } else {
+
+ if (aflcc->lto_mode)
+ final_ = PARAM_DROP;
+ else
+ final_ = PARAM_KEEP;
}
- }
+ } else if (!strcmp(cur_argv, "-Wl,-z,defs") ||
- if (strcmp(callname, "afl-clang") == 0 ||
- strcmp(callname, "afl-clang++") == 0) {
+ !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")) {
- clang_mode = 1;
- compiler_mode = CLANG;
+ if (scan) {
- if (strcmp(callname, "afl-clang++") == 0) { plusplus_mode = 1; }
+ final_ = PARAM_SCAN;
- }
+ } else {
- for (i = 1; i < argc; i++) {
+ final_ = PARAM_DROP;
- if (strncmp(argv[i], "--afl", 5) == 0) {
+ }
- if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) {
+ } else if (!strcmp(cur_argv, "-z") || !strcmp(cur_argv, "-Wl,-z")) {
- passthrough = 1;
- argv[i] = "-g"; // we have to overwrite it, -g is always good
- continue;
+ u8 *param = *(argv + 1);
+ if (param && (!strcmp(param, "defs") || !strcmp(param, "-Wl,defs"))) {
+
+ *skip_next = 1;
+
+ if (scan) {
+
+ final_ = PARAM_SCAN;
+
+ } else {
+
+ final_ = PARAM_DROP;
}
- if (compiler_mode && !be_quiet) {
+ }
+
+ }
+
+ // Try to warn user for some unsupported cases
+ if (scan && final_ == PARAM_MISS) {
+
+ u8 *ptr_ = NULL;
+
+ if (!strcmp(cur_argv, "-Xlinker") && (ptr_ = *(argv + 1))) {
+
+ if (!strcmp(ptr_, "defs")) {
+
+ WARNF("'-Xlinker' 'defs' detected. This may result in a bad link.");
+
+ } else if (strstr(ptr_, "-no-undefined")) {
WARNF(
- "--afl-... compiler mode supersedes the AFL_CC_COMPILER and "
- "symlink compiler selection!");
+ "'-Xlinker' '%s' detected. The latter option may be dropped and "
+ "result in a bad link.",
+ ptr_);
}
- ptr = argv[i];
- ptr += 5;
- while (*ptr == '-')
- ptr++;
+ } else if (!strncmp(cur_argv, "-Wl,", 4) &&
- if (strncasecmp(ptr, "LTO", 3) == 0) {
+ (u8 *)strrchr(cur_argv, ',') != (cur_argv + 3)) {
- compiler_mode = LTO;
+ ptr_ = cur_argv + 4;
- } else if (strncasecmp(ptr, "LLVM", 4) == 0) {
+ if (strstr(ptr_, "-shared") || strstr(ptr_, "-dynamiclib")) {
- compiler_mode = LLVM;
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may break shared "
+ "linking.",
+ ptr_);
- } else if (strncasecmp(ptr, "PCGUARD", 7) == 0 ||
+ }
- strncasecmp(ptr, "PC-GUARD", 8) == 0) {
+ if (strstr(ptr_, "-r,") || strstr(ptr_, "-i,") || strstr(ptr_, ",-r") ||
+ strstr(ptr_, ",-i") || strstr(ptr_, "--relocatable")) {
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_PCGUARD;
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may break partial "
+ "linking.",
+ ptr_);
- } else if (strcasecmp(ptr, "INSTRIM") == 0 ||
+ }
- strcasecmp(ptr, "CFG") == 0) {
+ if (strstr(ptr_, "defs") || strstr(ptr_, "no-undefined")) {
- FATAL(
- "InsTrim instrumentation was removed. Use a modern LLVM and "
- "PCGUARD (default in afl-cc).\n");
+ WARNF(
+ "'%s': multiple link options after '-Wl,' may enable report "
+ "unresolved symbol references and result in a bad link.",
+ ptr_);
- } else if (strcasecmp(ptr, "AFL") == 0 ||
+ }
- strcasecmp(ptr, "CLASSIC") == 0) {
+ }
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_CLASSIC;
+ }
- } else if (strcasecmp(ptr, "LLVMNATIVE") == 0 ||
+ if (final_ == PARAM_KEEP) insert_param(aflcc, cur_argv);
- strcasecmp(ptr, "NATIVE") == 0 ||
- strcasecmp(ptr, "LLVM-NATIVE") == 0) {
+ return final_;
- compiler_mode = LLVM;
- instrument_mode = INSTRUMENT_LLVMNATIVE;
+}
- } else if (strncasecmp(ptr, "GCC_P", 5) == 0 ||
+/* Add params to specify the linker used in LTO */
+void add_lto_linker(aflcc_state_t *aflcc) {
- strncasecmp(ptr, "GCC-P", 5) == 0 ||
- strncasecmp(ptr, "GCCP", 4) == 0) {
+ unsetenv("AFL_LD");
+ unsetenv("AFL_LD_CALLER");
- compiler_mode = GCC_PLUGIN;
+ u8 *ld_path = NULL;
+ if (getenv("AFL_REAL_LD")) {
- } else if (strcasecmp(ptr, "GCC") == 0) {
+ ld_path = strdup(getenv("AFL_REAL_LD"));
- compiler_mode = GCC;
+ } else {
- } else if (strncasecmp(ptr, "CLANG", 5) == 0) {
+ ld_path = strdup(AFL_REAL_LD);
- compiler_mode = CLANG;
+ }
- } else
+ if (!ld_path || !*ld_path) {
- FATAL("Unknown --afl-... compiler mode: %s\n", argv[i]);
+ if (ld_path) {
+
+ // Freeing empty string
+ free(ld_path);
}
+ ld_path = strdup("ld.lld");
+
}
- if (strlen(callname) > 2 &&
- (strncmp(callname + strlen(callname) - 2, "++", 2) == 0 ||
- strstr(callname, "-g++") != NULL))
- plusplus_mode = 1;
+ 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);
- if (getenv("USE_TRACE_PC") || getenv("AFL_USE_TRACE_PC") ||
- getenv("AFL_LLVM_USE_TRACE_PC") || getenv("AFL_TRACE_PC")) {
+}
- 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");
+/* Add params to launch SanitizerCoverageLTO.so when linking */
+void add_lto_passes(aflcc_state_t *aflcc) {
+
+#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
+
+ insert_param(aflcc, "-Wl,--allow-multiple-definition");
+
+}
+
+/* Add params to link with libAFLDriver.a on request */
+static void add_aflpplib(aflcc_state_t *aflcc) {
+
+ if (!aflcc->need_aflpplib) return;
+
+ u8 *afllib = find_object(aflcc, "libAFLDriver.a");
+
+ if (!be_quiet) {
+
+ OKF("Found '-fsanitize=fuzzer', replacing with libAFLDriver.a");
}
- if (have_instr_env && getenv("AFL_DONT_OPTIMIZE") && !be_quiet) {
+ if (!afllib) {
- WARNF(
- "AFL_LLVM_ALLOWLIST/DENYLIST and AFL_DONT_OPTIMIZE cannot be combined "
- "for file matching, only function matching!");
+ if (!be_quiet) {
+
+ WARNF(
+ "Cannot find 'libAFLDriver.a' to replace '-fsanitize=fuzzer' in "
+ "the flags - this will fail!");
+
+ }
+
+ } else {
+
+ insert_param(aflcc, afllib);
+
+#ifdef __APPLE__
+ insert_param(aflcc, "-Wl,-undefined");
+ insert_param(aflcc, "dynamic_lookup");
+#endif
}
- 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");
+/* Add params to link with runtimes depended by our instrumentation */
+void add_runtime(aflcc_state_t *aflcc) {
+
+ if (aflcc->preprocessor_only || aflcc->have_c || !aflcc->non_dash) {
+
+ /* 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;
}
- if (getenv("AFL_LLVM_CTX")) instrument_opt_mode |= INSTRUMENT_OPT_CTX;
- if (getenv("AFL_LLVM_CALLER")) instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ if (aflcc->compiler_mode != GCC_PLUGIN && aflcc->compiler_mode != GCC &&
+ !getenv("AFL_LLVM_NO_RPATH")) {
- if (getenv("AFL_LLVM_NGRAM_SIZE")) {
+ // 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)) {
- 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 *libdir_opt = strdup("-Wl,-rpath=" LLVM_LIBDIR);
+ insert_param(aflcc, libdir_opt);
+
+ }
}
- if (getenv("AFL_LLVM_CTX_K")) {
+#ifndef __ANDROID__
- 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) {
+ #define M32_ERR_MSG "-m32 is not supported by your compiler"
+ #define M64_ERR_MSG "-m64 is not supported by your compiler"
- setenv("AFL_LLVM_CALLER", "1", 1);
- unsetenv("AFL_LLVM_CTX_K");
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
+ if (aflcc->compiler_mode != GCC && aflcc->compiler_mode != CLANG) {
- } else {
+ switch (aflcc->bit_mode) {
+
+ 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;
+
+ 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;
- instrument_opt_mode |= INSTRUMENT_OPT_CTX_K;
+ 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;
}
- }
+ #if __AFL_CODE_COVERAGE
+ // Required for dladdr used in afl-compiler-rt.o
+ insert_param(aflcc, "-ldl");
+ #endif
- if (getenv("AFL_LLVM_INSTRUMENT")) {
+ #if !defined(__APPLE__) && !defined(__sun)
+ if (!aflcc->shared_linking && !aflcc->partial_linking)
+ insert_object(aflcc, "dynamic_list.txt", "-Wl,--dynamic-list=%s", 0);
+ #endif
- u8 *ptr2 = strtok(getenv("AFL_LLVM_INSTRUMENT"), ":,;");
+ #if defined(__APPLE__)
+ if (aflcc->shared_linking || aflcc->partial_linking) {
- while (ptr2) {
+ 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");
- if (strncasecmp(ptr2, "afl", strlen("afl")) == 0 ||
- strncasecmp(ptr2, "classic", strlen("classic")) == 0) {
+ }
- if (instrument_mode == INSTRUMENT_LTO) {
+ #endif
- instrument_mode = INSTRUMENT_CLASSIC;
- lto_mode = 1;
+ }
- } else if (!instrument_mode || instrument_mode == INSTRUMENT_AFL) {
+#endif
- instrument_mode = INSTRUMENT_AFL;
+ add_aflpplib(aflcc);
- } else {
+#if defined(USEMMAP) && !defined(__HAIKU__) && !__APPLE__
+ insert_param(aflcc, "-Wl,-lrt");
+#endif
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+}
- }
+/** Linking behaviors -----END----- **/
- }
+/** Miscellaneous routines -----BEGIN----- **/
- if (strncasecmp(ptr2, "pc-guard", strlen("pc-guard")) == 0 ||
- strncasecmp(ptr2, "pcguard", strlen("pcguard")) == 0) {
+/*
+ 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 (!instrument_mode || instrument_mode == INSTRUMENT_PCGUARD)
- instrument_mode = INSTRUMENT_PCGUARD;
- else
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+ u8 *afl_as = find_object(aflcc, "as");
- }
+ if (!afl_as) FATAL("Cannot find 'as' (symlink to 'afl-as').");
- if (strncasecmp(ptr2, "llvmnative", strlen("llvmnative")) == 0 ||
- strncasecmp(ptr2, "llvm-native", strlen("llvm-native")) == 0 ||
- strncasecmp(ptr2, "native", strlen("native")) == 0) {
+ u8 *slash = strrchr(afl_as, '/');
+ if (slash) *slash = 0;
- 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]);
+ insert_param(aflcc, "-B");
+ insert_param(aflcc, afl_as);
- }
+ if (aflcc->compiler_mode == CLANG) insert_param(aflcc, "-no-integrated-as");
- if (strncasecmp(ptr2, "llvmcodecov", strlen("llvmcodecov")) == 0 ||
- strncasecmp(ptr2, "llvm-codecov", strlen("llvm-codecov")) == 0) {
+}
- if (!instrument_mode || instrument_mode == INSTRUMENT_LLVMNATIVE) {
+/* Add params to launch the gcc plugins for instrumentation. */
+void add_gcc_plugin(aflcc_state_t *aflcc) {
- instrument_mode = INSTRUMENT_LLVMNATIVE;
- instrument_opt_mode |= INSTRUMENT_OPT_CODECOV;
+ if (aflcc->cmplog_mode) {
- } else {
+ insert_object(aflcc, "afl-gcc-cmplog-pass.so", "-fplugin=%s", 0);
+ insert_object(aflcc, "afl-gcc-cmptrs-pass.so", "-fplugin=%s", 0);
- FATAL("main instrumentation mode already set with %s",
- instrument_mode_string[instrument_mode]);
+ }
- }
+ insert_object(aflcc, "afl-gcc-pass.so", "-fplugin=%s", 0);
- }
+ insert_param(aflcc, "-fno-if-conversion");
+ insert_param(aflcc, "-fno-if-conversion2");
- if (strncasecmp(ptr2, "cfg", strlen("cfg")) == 0 ||
- strncasecmp(ptr2, "instrim", strlen("instrim")) == 0) {
+}
- FATAL(
- "InsTrim instrumentation was removed. Use a modern LLVM and "
- "PCGUARD (default in afl-cc).\n");
+/* Add some miscellaneous params required by our instrumentation. */
+void add_misc_params(aflcc_state_t *aflcc) {
- }
+ if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") ||
+ getenv("AFL_LLVM_LAF_ALL") || getenv("AFL_LLVM_CMPLOG") ||
+ aflcc->lto_mode) {
- if (strncasecmp(ptr2, "lto", strlen("lto")) == 0) {
+ 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");
- 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]);
+ }
- }
+ if (!aflcc->have_pic) { insert_param(aflcc, "-fPIC"); }
- if (strcasecmp(ptr2, "gcc") == 0) {
+ if (getenv("AFL_HARDEN")) {
- 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;
+ insert_param(aflcc, "-fstack-protector-all");
- }
+ if (!aflcc->fortify_set) add_defs_fortify(aflcc, 2);
- if (strcasecmp(ptr2, "clang") == 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;
+ if (!getenv("AFL_DONT_OPTIMIZE")) {
- }
+ 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, "ctx-", strlen("ctx-")) == 0 ||
- strncasecmp(ptr2, "kctx-", strlen("c-ctx-")) == 0 ||
- strncasecmp(ptr2, "k-ctx-", strlen("k-ctx-")) == 0) {
+ }
- u8 *ptr3 = ptr2;
- while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
- ptr3++;
+ if (aflcc->x_set) {
- if (!*ptr3) {
+ insert_param(aflcc, "-x");
+ insert_param(aflcc, "none");
- 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");
+ }
- }
+}
- 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);
+/*
+ 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) {
- if (ctx_k == 1) {
+ param_st final_ = PARAM_MISS;
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- setenv("AFL_LLVM_CALLER", "1", 1);
- unsetenv("AFL_LLVM_CTX_K");
+// MACRO START
+#define SCAN_KEEP(dst, src) \
+ do { \
+ \
+ if (scan) { \
+ \
+ dst = src; \
+ final_ = PARAM_SCAN; \
+ \
+ } else { \
+ \
+ final_ = PARAM_KEEP; \
+ \
+ } \
+ \
+ } while (0)
- } else {
+ // MACRO END
- instrument_opt_mode |= (INSTRUMENT_OPT_CTX_K);
- u8 *ptr4 = alloc_printf("%u", ctx_k);
- setenv("AFL_LLVM_CTX_K", ptr4, 1);
+ if (!strncasecmp(cur_argv, "-fpic", 5)) {
- }
+ SCAN_KEEP(aflcc->have_pic, 1);
- }
+ } else if (!strcmp(cur_argv, "-m32") ||
- if (strcasecmp(ptr2, "ctx") == 0) {
+ !strcmp(cur_argv, "armv7a-linux-androideabi")) {
- instrument_opt_mode |= INSTRUMENT_OPT_CTX;
- setenv("AFL_LLVM_CTX", "1", 1);
+ SCAN_KEEP(aflcc->bit_mode, 32);
- }
+ } else if (!strcmp(cur_argv, "-m64")) {
- if (strncasecmp(ptr2, "caller", strlen("caller")) == 0) {
+ SCAN_KEEP(aflcc->bit_mode, 64);
- instrument_opt_mode |= INSTRUMENT_OPT_CALLER;
- setenv("AFL_LLVM_CALLER", "1", 1);
+ } else if (strstr(cur_argv, "FORTIFY_SOURCE")) {
- }
+ SCAN_KEEP(aflcc->fortify_set, 1);
- if (strncasecmp(ptr2, "ngram", strlen("ngram")) == 0) {
+ } else if (!strcmp(cur_argv, "-x")) {
- u8 *ptr3 = ptr2 + strlen("ngram");
- while (*ptr3 && (*ptr3 < '0' || *ptr3 > '9'))
- ptr3++;
+ SCAN_KEEP(aflcc->x_set, 1);
- if (!*ptr3) {
+ } else if (!strcmp(cur_argv, "-E")) {
- 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->preprocessor_only, 1);
- }
+ } else if (!strcmp(cur_argv, "--target=wasm32-wasi")) {
- 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->passthrough, 1);
- }
+ } else if (!strcmp(cur_argv, "-c")) {
- ptr2 = strtok(NULL, ":,;");
+ SCAN_KEEP(aflcc->have_c, 1);
- }
+ } else if (!strcmp(cur_argv, "-static-libasan")) {
- }
+ SCAN_KEEP(aflcc->have_staticasan, 1);
- if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CALLER)) {
+ } else if (strstr(cur_argv, "librustc") && strstr(cur_argv, "_rt.asan.a")) {
- FATAL("you cannot set CTX and CALLER together");
+ SCAN_KEEP(aflcc->have_rust_asanrt, 1);
- }
+ } else if (!strcmp(cur_argv, "-fno-omit-frame-pointer")) {
- if ((instrument_opt_mode & INSTRUMENT_OPT_CTX) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+ SCAN_KEEP(aflcc->have_fp, 1);
- FATAL("you cannot set CTX and K-CTX together");
+ } else if (!strcmp(cur_argv, "-fvisibility=hidden")) {
- }
+ SCAN_KEEP(aflcc->have_hidden, 1);
- if ((instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
- (instrument_opt_mode & INSTRUMENT_OPT_CTX_K)) {
+ } else if (!strcmp(cur_argv, "-flto") || !strcmp(cur_argv, "-flto=full")) {
- FATAL("you cannot set CALLER and K-CTX together");
+ SCAN_KEEP(aflcc->have_flto, 1);
- }
+ } else if (!strncmp(cur_argv, "-D_FORTIFY_SOURCE",
- if (instrument_opt_mode && instrument_mode == INSTRUMENT_DEFAULT &&
- (compiler_mode == LLVM || compiler_mode == UNSET)) {
+ strlen("-D_FORTIFY_SOURCE"))) {
- instrument_mode = INSTRUMENT_CLASSIC;
- compiler_mode = LLVM;
+ SCAN_KEEP(aflcc->have_fortify, 1);
- }
+ } else if (!strncmp(cur_argv, "-fcf-protection", strlen("-fcf-protection"))) {
- if (!compiler_mode) {
+ SCAN_KEEP(aflcc->have_cfisan, 1);
- // 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;
+ } else if (!strncmp(cur_argv, "-O", 2)) {
+
+ SCAN_KEEP(aflcc->have_o, 1);
+
+ } else if (!strncmp(cur_argv, "-funroll-loop", 13)) {
+
+ SCAN_KEEP(aflcc->have_unroll, 1);
+
+ } else if (!strncmp(cur_argv, "--afl", 5)) {
+
+ if (scan)
+ final_ = PARAM_SCAN;
else
- FATAL("no compiler mode available");
+ final_ = PARAM_DROP;
- }
+ } else if (!strncmp(cur_argv, "-fno-unroll", 11)) {
- /* if our PCGUARD implementation is not available then silently switch to
- native LLVM PCGUARD */
- if (compiler_mode == CLANG &&
- (instrument_mode == INSTRUMENT_DEFAULT ||
- instrument_mode == INSTRUMENT_PCGUARD) &&
- find_object("SanitizerCoveragePCGUARD.so", argv[0]) == NULL) {
+ if (scan)
+ final_ = PARAM_SCAN;
+ else
+ final_ = PARAM_DROP;
- instrument_mode = INSTRUMENT_LLVMNATIVE;
+ } else if (!strcmp(cur_argv, "-pipe") && aflcc->compiler_mode == GCC_PLUGIN) {
- }
+ if (scan)
+ final_ = PARAM_SCAN;
+ else
+ 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
@@ -2107,36 +2719,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 "
+ " 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"
@@ -2210,7 +2830,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"
@@ -2225,7 +2845,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"
@@ -2241,7 +2861,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"
@@ -2254,6 +2874,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"
@@ -2265,7 +2889,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"
@@ -2279,10 +2903,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), "
@@ -2290,7 +2916,7 @@ 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_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 "
@@ -2318,9 +2944,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
@@ -2346,209 +2972,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) {
+}
+
+/* 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) {
- DEBUGF("cd '%s';", getthecwd());
- for (i = 0; i < argc; i++)
- SAYF(" '%s'", argv[i]);
- SAYF("\n");
- fflush(stdout);
- fflush(stderr);
+ 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 84ddefd8..87003b03 100644
--- a/src/afl-common.c
+++ b/src/afl-common.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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.
@@ -98,12 +98,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 +127,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 +426,7 @@ u8 *find_binary(u8 *fname) {
FATAL(
"Unexpected overflow when processing ENV. This should never "
- "happend.");
+ "had happened.");
}
@@ -1298,6 +1321,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 7322f1ad..0a77d61c 100644
--- a/src/afl-forkserver.c
+++ b/src/afl-forkserver.c
@@ -13,7 +13,7 @@
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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.
@@ -129,6 +129,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 +164,8 @@ void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
}
+ if (fsrv->nyx_log_fd >= 0) { close(fsrv->nyx_log_fd); }
+
}
}
@@ -214,6 +220,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 +272,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.
@@ -571,6 +579,22 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
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 +613,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 (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+ if (fsrv->nyx_handlers->nyx_config_set_aux_buffer_size(
+ nyx_config, fsrv->nyx_aux_string_len) != 1) {
- NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist");
+ 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("AFL_NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+
+ 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 +660,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 +675,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 +696,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;
@@ -974,6 +1017,14 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (rlen == 4) {
+ if (status >= 0x41464c00 && status <= 0x41464cff) {
+
+ FATAL(
+ "Target uses the new forkserver model, you need to switch to a newer "
+ "afl-fuzz too!");
+
+ }
+
if (!be_quiet) { OKF("All right - fork server is up."); }
if (getenv("AFL_DEBUG")) {
@@ -1581,7 +1632,7 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
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 +1646,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;
}
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index 556bb5d1..d056ac9f 100644
--- a/src/afl-fuzz-bitmap.c
+++ b/src/afl-fuzz-bitmap.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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;
@@ -533,6 +544,19 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
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) {
@@ -853,7 +877,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..21f34e12 100644
--- a/src/afl-fuzz-cmplog.c
+++ b/src/afl-fuzz-cmplog.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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..3b1d13f1 100644
--- a/src/afl-fuzz-extras.c
+++ b/src/afl-fuzz-extras.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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;
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index 13802f40..76291cc4 100644
--- a/src/afl-fuzz-init.c
+++ b/src/afl-fuzz-init.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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
}
@@ -942,6 +948,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 +958,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;
}
@@ -1058,7 +1094,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 +1121,101 @@ 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
+
+ snprintf(crash_fn, PATH_MAX, "%s/crashes/id:%06llu,sig:%02u,%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);
+
+#else
+
+ snprintf(crash_fn, PATH_MAX, "%s/crashes/id_%06llu_%02u",
+ afl->out_dir, afl->saved_crashes,
+ afl->fsrv.last_kill_signal);
+
+#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;
- afl->max_depth = 0;
- for (i = 0; i < afl->queued_items && likely(afl->queue_buf[i]); i++) {
+ }
+
+ if (i < afl->queued_items && afl->queue_buf[i]) {
+
+ afl->queue = afl->queue_buf[i];
- if (!afl->queue_buf[i]->disabled &&
- afl->queue_buf[i]->depth > afl->max_depth)
- afl->max_depth = afl->queue_buf[i]->depth;
+ } else {
+
+ afl->queue = afl->queue_buf[0];
+
+ }
+
+ 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;
+
+ }
}
+ q->disabled = 1;
+ q->perf_score = 0;
+
break;
case FSRV_RUN_ERROR:
@@ -1192,6 +1300,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 +1321,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;
@@ -1542,8 +1652,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; }
@@ -2126,6 +2236,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 +2324,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 +2352,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 +2491,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..ae4d6668 100644
--- a/src/afl-fuzz-mutators.c
+++ b/src/afl-fuzz-mutators.c
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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 5c71fc59..d9c074ec 100644
--- a/src/afl-fuzz-one.c
+++ b/src/afl-fuzz-one.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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) {
-
- memset(eff_map, 1, EFF_ALEN(len));
-
- afl->blocks_eff_select += EFF_ALEN(len);
-
- } else {
+ for (i = 0; i < len; i++) {
- 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)]) {
+ if (!skip_eff_map[i]) continue;
- afl->stage_max -= sizeof(interesting_8);
- 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) {
@@ -1932,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;
@@ -2055,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 */
@@ -2123,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) {
@@ -2170,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(
@@ -2201,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) =
@@ -2363,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) =
@@ -2402,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) =
@@ -2441,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) =
@@ -2480,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. */
@@ -2506,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 =
@@ -2530,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 =
@@ -2560,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,
@@ -2573,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)]++;
@@ -2640,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)]--;
@@ -2653,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_");
@@ -2666,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. */
@@ -2678,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) {
@@ -2695,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
@@ -2718,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. */
@@ -2731,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
@@ -2744,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. */
@@ -2881,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
@@ -3039,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;
@@ -3079,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:
@@ -3093,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;
+
+ }
}
@@ -3349,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. */
@@ -5556,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..16a398fd 100644
--- a/src/afl-fuzz-python.c
+++ b/src/afl-fuzz-python.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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..1ea50418 100644
--- a/src/afl-fuzz-queue.c
+++ b/src/afl-fuzz-queue.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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;
@@ -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 41644cb9..eead7a8b 100644
--- a/src/afl-fuzz-redqueen.c
+++ b/src/afl-fuzz-redqueen.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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.
@@ -40,7 +40,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
};
@@ -129,7 +129,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 +139,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 +155,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) {
@@ -571,7 +573,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 +657,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 +732,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 +747,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 +758,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 +770,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,
@@ -797,42 +806,77 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
}
- // 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) {
+
+ 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);
- // #ifdef CMPLOG_SOLVE_TRANSFORM
// 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) {
+
+ // 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)) {
- if (afl->queue_cur->is_ascii) {
+ if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum)) {
- endptr = buf_8;
- if (strntoll(buf_8, len - idx, (char **)&endptr, 0, &num)) {
+ use_unum = 1;
- if (!strntoull(buf_8, len - idx, (char **)&endptr, 0, &unum))
- use_unum = 1;
+ }
- } else
+ } else {
- use_num = 1;
+ 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 +925,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 +982,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
@@ -1269,13 +1292,141 @@ 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;
@@ -1536,6 +1687,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 +1828,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
@@ -1684,6 +1906,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
#endif
+ if (hshape < 2) { return 0; }
+
for (i = 0; i < loggeds; ++i) {
struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
@@ -1988,10 +2212,10 @@ 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; }
}
@@ -2009,8 +2233,14 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
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 +2251,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 +2285,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 +2297,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,9 +2327,7 @@ 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];
@@ -2144,7 +2380,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 +2400,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 +2424,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 +2469,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 +2557,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 +2593,36 @@ 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 {
+ }
- for (j = 0; j <= (i >> 1); j++) {
+ } else {
- tmp[off + (j << 1)] = hex_table_low[repl[j] >> 4];
- tmp[off + (j << 1) + 1] = hex_table_low[repl[j] % 16];
+ 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];
+
+ }
}
- }
+ memcpy(buf + idx, tmp, hlen + 1 + off);
+ if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
+ tmp[hlen + 1 + off] = 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, hlen + 1 + off);
- 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 +2671,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 +2686,6 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
}
- // #endif
-
return 0;
}
@@ -2429,11 +2695,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,19 +2720,23 @@ 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);
@@ -2481,7 +2753,7 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
for (j = 0; j < 8; j++)
fprintf(stderr, "%02x", orig_o->v1[j]);
fprintf(stderr, "\n");
- */
+#endif
t = taint;
while (t->next) {
@@ -2515,7 +2787,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 +2864,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 +2877,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++;
}
@@ -2816,12 +3090,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..d764952c 100644
--- a/src/afl-fuzz-run.c
+++ b/src/afl-fuzz-run.c
@@ -10,7 +10,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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);
}
@@ -918,7 +912,7 @@ 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)) { return 0; }
afl->stage_name = afl->stage_name_buf;
afl->bytes_trim_in += q->len;
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..4467cae8 100644
--- a/src/afl-fuzz-state.c
+++ b/src/afl-fuzz-state.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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.
@@ -89,9 +89,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 */
@@ -108,6 +107,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
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 +140,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 +207,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 +276,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)) {
@@ -301,6 +323,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)) {
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 07157bf7..76577081 100644
--- a/src/afl-fuzz-stats.c
+++ b/src/afl-fuzz-stats.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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,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) {
@@ -206,11 +250,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 +288,8 @@ 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 = afl->prev_run_time + cur_time - afl->start_time;
+ if (!runtime) { runtime = 1; }
fprintf(
f,
@@ -290,17 +338,14 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"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(),
+ runtime / 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),
+ afl->fsrv.total_execs, afl->fsrv.total_execs / ((double)(runtime) / 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 +413,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
}
fclose(f);
+ rename(fn_tmp, fn_final);
}
@@ -456,6 +502,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) {
@@ -734,10 +818,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 +857,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__
@@ -995,7 +1097,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);
@@ -1282,7 +1384,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
@@ -1823,7 +1929,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 +2366,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 +2413,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.",
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 4134b99e..12d67fe7 100644
--- a/src/afl-fuzz.c
+++ b/src/afl-fuzz.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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 +125,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 +165,30 @@ 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"
+ " -D - enable (a new) effective deterministic fuzzing\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"
@@ -212,7 +225,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) {
@@ -252,6 +266,7 @@ static void usage(u8 *argv0, int more_help) {
"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 +277,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 +303,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 +319,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 +331,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 +381,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
@@ -458,6 +486,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 +531,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:YZ")) > 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 +629,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,14 +955,20 @@ int main(int argc, char **argv_orig, char **envp) {
break;
- case 'D': /* enforce deterministic */
+ case 'D': /* partial deterministic */
afl->skip_deterministic = 0;
break;
- case 'd': /* skip deterministic */
+ case 'd': /* no deterministic */
- afl->skip_deterministic = 1;
+ // this is the default and currently a lot of infrastructure enforces
+ // it (e.g. clusterfuzz, fuzzbench) based on that this feature
+ // originally was bad performance wise. We now have a better
+ // implementation, hence if it is activated, we do not want to
+ // deactivate it by such setups.
+
+ // afl->skip_deterministic = 1;
break;
case 'B': /* load bitmap */
@@ -1056,10 +1172,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;
@@ -1221,6 +1345,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 +1370,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 +1430,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 +1530,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");
}
@@ -1436,8 +1570,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 +1755,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);
@@ -1657,6 +1818,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(
@@ -1756,6 +1921,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);
@@ -2274,7 +2448,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);
}
@@ -2319,6 +2493,7 @@ int main(int argc, char **argv_orig, char **envp) {
max_ms = afl->queue_buf[entry]->exec_us;
afl->fsrv.exec_tmout = max_ms;
+ afl->timeout_given = 1;
}
@@ -2611,22 +2786,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];
+
+ }
}
@@ -2688,13 +2893,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))) {
@@ -2707,7 +2933,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); }
@@ -2790,6 +3016,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];
@@ -2801,6 +3037,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);
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
index 4f851099..7aee2985 100644
--- a/src/afl-gotcpu.c
+++ b/src/afl-gotcpu.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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..513c1ae9 100644
--- a/src/afl-ld-lto.c
+++ b/src/afl-ld-lto.c
@@ -9,7 +9,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Dominik Maier <domenukk@gmail.com>
- Copyright 2019-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..07c1b527 100644
--- a/src/afl-performance.c
+++ b/src/afl-performance.c
@@ -1,24 +1,3 @@
-/*
- 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"
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index a2c81586..daea8f46 100644
--- a/src/afl-sharedmem.c
+++ b/src/afl-sharedmem.c
@@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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..20ba5a5e 100644
--- a/src/afl-showmap.c
+++ b/src/afl-showmap.c
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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
};
@@ -243,7 +244,8 @@ static void analyze_results(afl_forkserver_t *fsrv) {
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 (!coverage_map[i]) { coverage_map[i] = 1; }
+ coverage_map[i] |= fsrv->trace_bits[i];
}
@@ -328,7 +330,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 +425,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 +656,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 {
@@ -1609,6 +1611,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");
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index e7442d1d..4e5dab41 100644
--- a/src/afl-tmin.c
+++ b/src/afl-tmin.c
@@ -12,7 +12,7 @@
Dominik Maier <mail@dmnk.co>
Copyright 2016, 2017 Google Inc. All rights reserved.
- Copyright 2019-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.