aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/afl-analyze.c154
-rw-r--r--src/afl-as.c24
-rw-r--r--src/afl-cc.c135
-rw-r--r--src/afl-common.c139
-rw-r--r--src/afl-forkserver.c329
-rw-r--r--src/afl-fuzz-bitmap.c58
-rw-r--r--src/afl-fuzz-cmplog.c12
-rw-r--r--src/afl-fuzz-extras.c2
-rw-r--r--src/afl-fuzz-init.c84
-rw-r--r--src/afl-fuzz-mutators.c43
-rw-r--r--src/afl-fuzz-one.c179
-rw-r--r--src/afl-fuzz-python.c77
-rw-r--r--src/afl-fuzz-queue.c134
-rw-r--r--src/afl-fuzz-redqueen.c6
-rw-r--r--src/afl-fuzz-run.c36
-rw-r--r--src/afl-fuzz-state.c55
-rw-r--r--src/afl-fuzz-stats.c142
-rw-r--r--src/afl-fuzz.c228
-rw-r--r--src/afl-gotcpu.c21
-rw-r--r--src/afl-ld-lto.c2
-rw-r--r--src/afl-sharedmem.c2
-rw-r--r--src/afl-showmap.c509
-rw-r--r--src/afl-tmin.c148
23 files changed, 1793 insertions, 726 deletions
diff --git a/src/afl-analyze.c b/src/afl-analyze.c
index a9b5b326..5b122741 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -121,9 +121,9 @@ static void kill_child() {
}
-static void classify_counts(u8 *mem) {
+static void classify_counts(u8 *mem, u32 mem_size) {
- u32 i = map_size;
+ u32 i = mem_size;
if (edges_only) {
@@ -222,7 +222,7 @@ static u64 analyze_run_target(u8 *mem, u32 len, u8 first_run) {
}
- classify_counts(fsrv.trace_bits);
+ classify_counts(fsrv.trace_bits, fsrv.map_size);
total_execs++;
if (stop_soon) {
@@ -656,28 +656,6 @@ static void set_up_environment(char **argv) {
if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); }
/* Set sane defaults... */
-
- x = get_afl_env("ASAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "abort_on_error=1")) {
-
- FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
-
- }
-
-#ifndef ASAN_BUILD
- if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
-
- FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
-#endif
-
- }
-
x = get_afl_env("MSAN_OPTIONS");
if (x) {
@@ -689,69 +667,9 @@ static void set_up_environment(char **argv) {
}
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
}
- x = get_afl_env("LSAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
- }
-
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "detect_odr_violation=0:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -807,7 +725,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -846,6 +768,7 @@ static void usage(u8 *argv0) {
" -U - use unicorn-based instrumentation (Unicorn mode)\n"
" -W - use qemu-based instrumentation with Wine (Wine "
"mode)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
@@ -892,7 +815,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl_fsrv_init(&fsrv);
- while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:f:m:t:eAOQUWXYh")) > 0) {
switch (opt) {
@@ -1044,6 +967,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv.nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv.nyx_mode = 1;
+ fsrv.nyx_parent = true;
+ fsrv.nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'h':
usage(argv[0]);
return -1;
@@ -1075,7 +1015,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(argv);
+#ifdef __linux__
+ if (!fsrv.nyx_mode) {
+
+ fsrv.target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv.target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv.target_path = find_binary(argv[optind]);
+#endif
+
fsrv.trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, fsrv.out_file, &use_stdin);
signal(SIGALRM, kill_child);
@@ -1098,6 +1052,26 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv = get_cs_argv(argv[0], &target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv.nyx_mode) {
+
+ fsrv.nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+ fsrv.nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv.nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv.nyx_use_tmp_workdir = true;
+ fsrv.nyx_bind_cpu_id = 0;
+
+ use_argv = argv + optind;
+#endif
+
} else {
use_argv = argv + optind;
@@ -1123,7 +1097,11 @@ int main(int argc, char **argv_orig, char **envp) {
&fsrv, NULL, NULL, (fsrv.qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
read_initial_file();
+#ifdef __linux__
+ if (!fsrv.nyx_mode) { (void)check_binary_signatures(fsrv.target_path); }
+#else
(void)check_binary_signatures(fsrv.target_path);
+#endif
ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...",
mem_limit, exec_tmout, edges_only ? ", edges only" : "");
diff --git a/src/afl-as.c b/src/afl-as.c
index 1edc8cca..772e31b3 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -93,7 +93,7 @@ static u8 use_64bit = 0;
static void edit_params(int argc, char **argv) {
u8 *tmp_dir = getenv("TMPDIR"), *afl_as = getenv("AFL_AS");
- u32 i;
+ u32 i, input_index;
#ifdef __APPLE__
@@ -142,7 +142,23 @@ static void edit_params(int argc, char **argv) {
as_params[argc] = 0;
- for (i = 1; (s32)i < argc - 1; i++) {
+ /* Find the input file. It's usually located near the end.
+ Assume there won't be any arguments referring to files after the input
+ file, e.g. as input.s -o output.o */
+ for (input_index = argc - 1; input_index > 0; input_index--) {
+
+ input_file = argv[input_index];
+ /* Clang may add debug arguments after the input file. */
+ if (strncmp(input_file, "-g", 2)) break;
+
+ }
+
+ if (input_index == 0)
+ FATAL("Could not find input file (not called through afl-gcc?)");
+
+ for (i = 1; (s32)i < argc; i++) {
+
+ if (i == input_index) continue;
if (!strcmp(argv[i], "--64")) {
@@ -194,8 +210,6 @@ static void edit_params(int argc, char **argv) {
#endif /* __APPLE__ */
- input_file = argv[argc - 1];
-
if (input_file[0] == '-') {
if (!strcmp(input_file + 1, "-version")) {
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 1c3b5405..d1001187 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -1050,17 +1050,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (getenv("AFL_USE_CFISAN")) {
- if (!lto_mode) {
+ if (compiler_mode == GCC_PLUGIN || compiler_mode == GCC) {
- 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";
+ cc_params[cc_par_cnt++] = "-fcf-protection=full";
- }
+ } else {
+
+ if (!lto_mode) {
+
+ 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";
+
+ }
- cc_params[cc_par_cnt++] = "-fsanitize=cfi";
- cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+ cc_params[cc_par_cnt++] = "-fsanitize=cfi";
+ cc_params[cc_par_cnt++] = "-fvisibility=hidden";
+
+ }
}
@@ -1093,37 +1101,45 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (!have_c) cc_params[cc_par_cnt++] = "-lrt";
#endif
- cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=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:
+ /* 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) {
+
+ cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
- 1) We need to convince the compiler not to optimize out the signature.
- This is done with __attribute__((used)).
+ /* 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:
- 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.
+ 1) We need to convince the compiler not to optimize out the signature.
+ This is done with __attribute__((used)).
- 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.
+ 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.
- 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;";
+ */
+
+ 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;";
+
+ }
if (plusplus_mode) {
@@ -1161,35 +1177,39 @@ static void edit_params(u32 argc, char **argv, char **envp) {
"(*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff "
"? 0 : *__afl_fuzz_len)";
- cc_params[cc_par_cnt++] =
- "-D__AFL_LOOP(_A)="
- "({ static volatile char *_B __attribute__((used,unused)); "
- " _B = (char*)\"" PERSIST_SIG
- "\"; "
- "extern int __afl_connected;"
+ if (compiler_mode != GCC && compiler_mode != CLANG) {
+
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_LOOP(_A)="
+ "({ static volatile const char *_B __attribute__((used,unused)); "
+ " _B = (const char*)\"" PERSIST_SIG
+ "\"; "
+ "extern int __afl_connected;"
#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "int _L(unsigned int) __asm__(\"___afl_persistent_loop\"); "
+ "__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); })";
+ // 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 char *_A __attribute__((used,unused)); "
- " _A = (char*)\"" DEFER_SIG
- "\"; "
+ cc_params[cc_par_cnt++] =
+ "-D__AFL_INIT()="
+ "do { static volatile const char *_A __attribute__((used,unused)); "
+ " _A = (const char*)\"" DEFER_SIG
+ "\"; "
#ifdef __APPLE__
- "__attribute__((visibility(\"default\"))) "
- "void _I(void) __asm__(\"___afl_manual_init\"); "
+ "__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) {
@@ -2033,6 +2053,8 @@ int main(int argc, char **argv, char **envp) {
" AFL_LLVM_DICT2FILE: generate an afl dictionary based on found "
"comparisons\n"
+ " AFL_LLVM_DICT2FILE_NO_MAIN: skip parsing main() for the "
+ "dictionary\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"
@@ -2077,6 +2099,8 @@ int main(int argc, char **argv, char **envp) {
"bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n"
+ " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "
+ "(used in WAFL mode)\n"
"If anything fails - be sure to read README.lto.md!\n");
#endif
@@ -2120,7 +2144,8 @@ int main(int argc, char **argv, char **envp) {
"defaults.\n"
"Recommended is afl-clang-lto with AFL_LLVM_CMPLOG or afl-clang-fast "
"with\n"
- "AFL_LLVM_CMPLOG and AFL_LLVM_DICT2FILE.\n\n");
+ "AFL_LLVM_CMPLOG and "
+ "AFL_LLVM_DICT2FILE+AFL_LLVM_DICT2FILE_NO_MAIN.\n\n");
exit(1);
diff --git a/src/afl-common.c b/src/afl-common.c
index 31005804..a5c48e80 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -58,6 +58,90 @@ u8 last_intr = 0;
#define AFL_PATH "/usr/local/lib/afl/"
#endif
+void *afl_memmem(const void *haystack, size_t haystacklen, const void *needle,
+ size_t needlelen) {
+
+ if (unlikely(needlelen > haystacklen)) { return NULL; }
+
+ for (u32 i = 0; i <= haystacklen - needlelen; ++i) {
+
+ if (unlikely(memcmp(haystack + i, needle, needlelen) == 0)) {
+
+ return (void *)(haystack + i);
+
+ }
+
+ }
+
+ return (void *)NULL;
+
+}
+
+void set_sanitizer_defaults() {
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+ u8 *have_asan_options = getenv("ASAN_OPTIONS");
+ u8 *have_ubsan_options = getenv("UBSAN_OPTIONS");
+ u8 *have_msan_options = getenv("MSAN_OPTIONS");
+ u8 *have_lsan_options = getenv("LSAN_OPTIONS");
+ u8 have_san_options = 0;
+ u8 default_options[1024] =
+ "detect_odr_violation=0:abort_on_error=1:symbolize=0:allocator_may_"
+ "return_null=1:handle_segv=0:handle_sigbus=0:handle_abort=0:handle_"
+ "sigfpe=0:handle_sigill=0:";
+
+ if (have_asan_options || have_ubsan_options || have_msan_options ||
+ have_lsan_options) {
+
+ have_san_options = 1;
+
+ }
+
+ /* LSAN does not support abort_on_error=1. (is this still true??) */
+
+ 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:");
+ setenv("LSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* for everything not LSAN we disable detect_leaks */
+
+ if (!have_lsan_options) {
+
+ strcat(default_options, "detect_leaks=0:malloc_context_size=0:");
+
+ }
+
+ /* Set sane defaults for ASAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("ASAN_OPTIONS", default_options, 1); }
+
+ /* Set sane defaults for UBSAN if nothing else is specified. */
+
+ if (!have_san_options) { setenv("UBSAN_OPTIONS", default_options, 1); }
+
+ /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
+ point. So, we do this in a very hacky way. */
+
+ if (!have_msan_options) {
+
+ u8 buf[2048] = "";
+ if (!have_san_options) { strcpy(buf, default_options); }
+ strcat(buf, "exit_code=" STRINGIFY(MSAN_ERROR) ":msan_track_origins=0:");
+ setenv("MSAN_OPTIONS", buf, 1);
+
+ }
+
+ /* Envs for QASan */
+ setenv("QASAN_MAX_CALL_STACK", "0", 0);
+ setenv("QASAN_SYMBOLIZE", "0", 0);
+
+}
+
u32 check_binary_signatures(u8 *fn) {
int ret = 0, fd = open(fn, O_RDONLY);
@@ -69,7 +153,7 @@ u32 check_binary_signatures(u8 *fn) {
if (f_data == MAP_FAILED) { PFATAL("Unable to mmap file '%s'", fn); }
close(fd);
- if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+ if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Persistent mode binary detected."); }
setenv(PERSIST_ENV_VAR, "1", 1);
@@ -94,7 +178,7 @@ u32 check_binary_signatures(u8 *fn) {
}
- if (memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+ if (afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
if (!be_quiet) { OKF(cPIN "Deferred forkserver binary detected."); }
setenv(DEFER_ENV_VAR, "1", 1);
@@ -1275,3 +1359,52 @@ s32 create_file(u8 *fn) {
}
+#ifdef __linux__
+
+/* Nyx requires a tmp workdir to access specific files (such as mmapped files,
+ * etc.). This helper function basically creates both a path to a tmp workdir
+ * and the workdir itself. If the environment variable TMPDIR is set, we use
+ * that as the base directory, otherwise we use /tmp. */
+char *create_nyx_tmp_workdir(void) {
+
+ char *tmpdir = getenv("TMPDIR");
+
+ if (!tmpdir) { tmpdir = "/tmp"; }
+
+ char *nyx_out_dir_path =
+ alloc_printf("%s/.nyx_tmp_%d/", tmpdir, (u32)getpid());
+
+ if (mkdir(nyx_out_dir_path, 0700)) { PFATAL("Unable to create nyx workdir"); }
+
+ return nyx_out_dir_path;
+
+}
+
+/* Vice versa, we remove the tmp workdir for nyx with this helper function. */
+void remove_nyx_tmp_workdir(afl_forkserver_t *fsrv, char *nyx_out_dir_path) {
+
+ char *workdir_path = alloc_printf("%s/workdir", nyx_out_dir_path);
+
+ if (access(workdir_path, R_OK) == 0) {
+
+ if (fsrv->nyx_handlers->nyx_remove_work_dir(workdir_path) != true) {
+
+ WARNF("Unable to remove nyx workdir (%s)", workdir_path);
+
+ }
+
+ }
+
+ if (rmdir(nyx_out_dir_path)) {
+
+ WARNF("Unable to remove nyx workdir (%s)", nyx_out_dir_path);
+
+ }
+
+ ck_free(workdir_path);
+ ck_free(nyx_out_dir_path);
+
+}
+
+#endif
+
diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c
index a241f2c6..aa8c8622 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -49,6 +49,134 @@
#include <sys/select.h>
#include <sys/stat.h>
+#ifdef __linux__
+ #include <dlfcn.h>
+
+/* function to load nyx_helper function from libnyx.so */
+
+nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
+
+ void *handle;
+ nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
+
+ ACTF("Trying to load libnyx.so plugin...");
+ handle = dlopen((char *)libnyx_binary, RTLD_NOW);
+ if (!handle) { goto fail; }
+
+ plugin->nyx_config_load = dlsym(handle, "nyx_config_load");
+ if (plugin->nyx_config_load == NULL) { goto fail; }
+
+ plugin->nyx_config_set_workdir_path =
+ dlsym(handle, "nyx_config_set_workdir_path");
+ if (plugin->nyx_config_set_workdir_path == NULL) { goto fail; }
+
+ plugin->nyx_config_set_input_buffer_size =
+ dlsym(handle, "nyx_config_set_input_buffer_size");
+ if (plugin->nyx_config_set_input_buffer_size == NULL) { goto fail; }
+
+ plugin->nyx_config_set_input_buffer_write_protection =
+ dlsym(handle, "nyx_config_set_input_buffer_write_protection");
+ if (plugin->nyx_config_set_input_buffer_write_protection == NULL) {
+
+ goto fail;
+
+ }
+
+ plugin->nyx_config_set_hprintf_fd =
+ dlsym(handle, "nyx_config_set_hprintf_fd");
+ if (plugin->nyx_config_set_hprintf_fd == NULL) { goto fail; }
+
+ plugin->nyx_config_set_process_role =
+ dlsym(handle, "nyx_config_set_process_role");
+ if (plugin->nyx_config_set_process_role == NULL) { goto fail; }
+
+ plugin->nyx_config_set_reuse_snapshot_path =
+ dlsym(handle, "nyx_config_set_reuse_snapshot_path");
+ if (plugin->nyx_config_set_reuse_snapshot_path == NULL) { goto fail; }
+
+ plugin->nyx_new = dlsym(handle, "nyx_new");
+ if (plugin->nyx_new == NULL) { goto fail; }
+
+ plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
+ if (plugin->nyx_shutdown == NULL) { goto fail; }
+
+ plugin->nyx_option_set_reload_mode =
+ dlsym(handle, "nyx_option_set_reload_mode");
+ if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
+
+ plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
+ if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
+
+ plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
+ if (plugin->nyx_option_apply == NULL) { goto fail; }
+
+ plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
+ if (plugin->nyx_set_afl_input == NULL) { goto fail; }
+
+ plugin->nyx_exec = dlsym(handle, "nyx_exec");
+ if (plugin->nyx_exec == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
+ if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
+
+ plugin->nyx_get_bitmap_buffer_size =
+ dlsym(handle, "nyx_get_bitmap_buffer_size");
+ if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
+
+ plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
+ if (plugin->nyx_get_aux_string == NULL) { goto fail; }
+
+ plugin->nyx_remove_work_dir = dlsym(handle, "nyx_remove_work_dir");
+ if (plugin->nyx_remove_work_dir == NULL) { goto fail; }
+
+ OKF("libnyx plugin is ready!");
+ return plugin;
+
+fail:
+
+ FATAL("failed to load libnyx: %s\n", dlerror());
+ ck_free(plugin);
+ return NULL;
+
+}
+
+void afl_nyx_runner_kill(afl_forkserver_t *fsrv) {
+
+ if (fsrv->nyx_mode) {
+
+ if (fsrv->nyx_aux_string) { ck_free(fsrv->nyx_aux_string); }
+
+ /* check if we actually got a valid nyx runner */
+ if (fsrv->nyx_runner) {
+
+ fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
+
+ }
+
+ /* if we have use a tmp work dir we need to remove it */
+ if (fsrv->nyx_use_tmp_workdir && fsrv->nyx_tmp_workdir_path) {
+
+ remove_nyx_tmp_workdir(fsrv, fsrv->nyx_tmp_workdir_path);
+
+ }
+
+ }
+
+}
+
+ /* Wrapper for FATAL() that kills the nyx runner (and removes all created tmp
+ * files) before exiting. Used before "afl_fsrv_killall()" is registered as
+ * an atexit() handler. */
+ #define NYX_PRE_FATAL(fsrv, x...) \
+ do { \
+ \
+ afl_nyx_runner_kill(fsrv); \
+ FATAL(x); \
+ \
+ } while (0)
+
+#endif
+
/**
* The correct fds for reading and writing pipes
*/
@@ -84,6 +212,8 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) {
fsrv->nyx_runner = NULL;
fsrv->nyx_id = 0xFFFFFFFF;
fsrv->nyx_bind_cpu_id = 0xFFFFFFFF;
+ fsrv->nyx_use_tmp_workdir = false;
+ fsrv->nyx_tmp_workdir_path = NULL;
#endif
// this structure needs default so we initialize it if this was not done
@@ -397,40 +527,119 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!be_quiet) { ACTF("Spinning up the NYX backend..."); }
- if (fsrv->out_dir_path == NULL) { FATAL("Nyx workdir path not found..."); }
+ if (fsrv->nyx_use_tmp_workdir) {
+
+ fsrv->nyx_tmp_workdir_path = create_nyx_tmp_workdir();
+ fsrv->out_dir_path = fsrv->nyx_tmp_workdir_path;
+
+ } else {
+
+ if (fsrv->out_dir_path == NULL) {
+
+ NYX_PRE_FATAL(fsrv, "Nyx workdir path not found...");
+
+ }
+
+ }
+
+ /* libnyx expects an absolute path */
+ char *outdir_path_absolute = realpath(fsrv->out_dir_path, NULL);
+ if (outdir_path_absolute == NULL) {
- char *x = alloc_printf("%s/workdir", fsrv->out_dir_path);
+ NYX_PRE_FATAL(fsrv, "Nyx workdir path cannot be resolved ...");
- if (fsrv->nyx_id == 0xFFFFFFFF) { FATAL("Nyx ID is not set..."); }
+ }
+
+ char *workdir_path = alloc_printf("%s/workdir", outdir_path_absolute);
+
+ if (fsrv->nyx_id == 0xFFFFFFFF) {
+
+ NYX_PRE_FATAL(fsrv, "Nyx ID is not set...");
+
+ }
if (fsrv->nyx_bind_cpu_id == 0xFFFFFFFF) {
- FATAL("Nyx CPU ID is not set...");
+ NYX_PRE_FATAL(fsrv, "Nyx CPU ID is not set...");
}
+ void *nyx_config = fsrv->nyx_handlers->nyx_config_load(fsrv->target_path);
+
+ fsrv->nyx_handlers->nyx_config_set_workdir_path(nyx_config, workdir_path);
+ fsrv->nyx_handlers->nyx_config_set_input_buffer_size(nyx_config, MAX_FILE);
+ fsrv->nyx_handlers->nyx_config_set_input_buffer_write_protection(nyx_config,
+ true);
+
if (fsrv->nyx_standalone) {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, StandAlone);
} else {
if (fsrv->nyx_parent) {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_parent(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, MAX_FILE, true);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Parent);
} else {
- fsrv->nyx_runner = fsrv->nyx_handlers->nyx_new_child(
- fsrv->target_path, x, fsrv->nyx_bind_cpu_id, fsrv->nyx_id);
+ fsrv->nyx_handlers->nyx_config_set_process_role(nyx_config, Child);
+
+ }
+
+ }
+
+ if (getenv("NYX_REUSE_SNAPSHOT") != NULL) {
+
+ if (access(getenv("NYX_REUSE_SNAPSHOT"), F_OK) == -1) {
+
+ NYX_PRE_FATAL(fsrv, "NYX_REUSE_SNAPSHOT path does not exist");
+
+ }
+
+ /* stupid sanity check to avoid passing an empty or invalid snapshot
+ * directory */
+ char *snapshot_file_path =
+ alloc_printf("%s/global.state", getenv("NYX_REUSE_SNAPSHOT"));
+ if (access(snapshot_file_path, R_OK) == -1) {
+
+ NYX_PRE_FATAL(
+ fsrv,
+ "NYX_REUSE_SNAPSHOT path does not contain a valid Nyx snapshot");
+
+ }
+
+ ck_free(snapshot_file_path);
+
+ /* another sanity check to avoid passing a snapshot directory that is
+ * located in the current workdir (the workdir will be wiped by libnyx on
+ * startup) */
+ char *workdir_snapshot_path =
+ alloc_printf("%s/workdir/snapshot", outdir_path_absolute);
+ char *reuse_snapshot_path_real =
+ realpath(getenv("NYX_REUSE_SNAPSHOT"), NULL);
+
+ if (strcmp(workdir_snapshot_path, reuse_snapshot_path_real) == 0) {
+
+ NYX_PRE_FATAL(fsrv,
+ "NYX_REUSE_SNAPSHOT path is located in current workdir "
+ "(use another output directory)");
}
+ ck_free(reuse_snapshot_path_real);
+ ck_free(workdir_snapshot_path);
+
+ fsrv->nyx_handlers->nyx_config_set_reuse_snapshot_path(
+ nyx_config, getenv("NYX_REUSE_SNAPSHOT"));
+
}
- ck_free(x);
+ fsrv->nyx_runner =
+ fsrv->nyx_handlers->nyx_new(nyx_config, fsrv->nyx_bind_cpu_id);
+
+ ck_free(workdir_path);
+ ck_free(outdir_path_absolute);
if (fsrv->nyx_runner == NULL) { FATAL("Something went wrong ..."); }
@@ -458,15 +667,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
switch (fsrv->nyx_handlers->nyx_exec(fsrv->nyx_runner)) {
case Abort:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
- FATAL("Error: Nyx abort occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx abort occured...");
break;
case IoError:
- FATAL("Error: QEMU-Nyx has died...");
+ NYX_PRE_FATAL(fsrv, "Error: QEMU-Nyx has died...");
break;
case Error:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
- FATAL("Error: Nyx runtime error has occured...");
+ NYX_PRE_FATAL(fsrv, "Error: Nyx runtime error has occured...");
break;
default:
break;
@@ -476,7 +683,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
/* autodict in Nyx mode */
if (!ignore_autodict) {
- x = alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
+ char *x =
+ alloc_printf("%s/workdir/dump/afl_autodict.txt", fsrv->out_dir_path);
int nyx_autodict_fd = open(x, O_RDONLY);
ck_free(x);
@@ -489,8 +697,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
u8 *dict = ck_alloc(f_len);
if (dict == NULL) {
- FATAL("Could not allocate %u bytes of autodictionary memory",
- f_len);
+ NYX_PRE_FATAL(
+ fsrv, "Could not allocate %u bytes of autodictionary memory",
+ f_len);
}
@@ -507,7 +716,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} else {
- FATAL(
+ NYX_PRE_FATAL(
+ fsrv,
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
@@ -688,70 +898,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (!getenv("LD_BIND_LAZY")) { setenv("LD_BIND_NOW", "1", 1); }
- /* Set sane defaults for ASAN if nothing else is specified. */
-
- if (!getenv("ASAN_OPTIONS"))
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "malloc_context_size=0:"
- "symbolize=0:"
- "allocator_may_return_null=1:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* Set sane defaults for UBSAN if nothing else is specified. */
-
- if (!getenv("UBSAN_OPTIONS"))
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* Envs for QASan */
- setenv("QASAN_MAX_CALL_STACK", "0", 0);
- setenv("QASAN_SYMBOLIZE", "0", 0);
-
- /* MSAN is tricky, because it doesn't support abort_on_error=1 at this
- point. So, we do this in a very hacky way. */
-
- if (!getenv("MSAN_OPTIONS"))
- setenv("MSAN_OPTIONS",
- "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "symbolize=0:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "msan_track_origins=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 1);
-
- /* LSAN, too, does not support abort_on_error=1. */
-
- if (!getenv("LSAN_OPTIONS"))
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 1);
+ /* Set sane defaults for sanitizers */
+ set_sanitizer_defaults();
fsrv->init_child_func(fsrv, argv);
@@ -1256,13 +1404,7 @@ void afl_fsrv_kill(afl_forkserver_t *fsrv) {
fsrv->child_pid = -1;
#ifdef __linux__
- if (fsrv->nyx_mode) {
-
- free(fsrv->nyx_aux_string);
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
-
- }
-
+ afl_nyx_runner_kill(fsrv);
#endif
}
@@ -1432,14 +1574,13 @@ afl_fsrv_run_target(afl_forkserver_t *fsrv, u32 timeout,
case Crash:
case Asan:
return FSRV_RUN_CRASH;
- case Timout:
+ case Timeout:
return FSRV_RUN_TMOUT;
case InvalidWriteToPayload:
/* ??? */
FATAL("FixMe: Nyx InvalidWriteToPayload handler is missing");
break;
case Abort:
- fsrv->nyx_handlers->nyx_shutdown(fsrv->nyx_runner);
FATAL("Error: Nyx abort occured...");
case IoError:
if (*stop_soon_p) {
diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c
index b3a10bb7..556bb5d1 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -457,9 +457,16 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (unlikely(len == 0)) { return 0; }
+ if (unlikely(fault == FSRV_RUN_TMOUT && afl->afl_env.afl_ignore_timeouts)) {
+
+ return 0;
+
+ }
+
u8 fn[PATH_MAX];
u8 *queue_fn = "";
- u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0;
+ u8 new_bits = 0, keeping = 0, res, classified = 0, is_timeout = 0,
+ need_hash = 1;
s32 fd;
u64 cksum = 0;
@@ -469,10 +476,14 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
only be used for special schedules */
if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+ classify_counts(&afl->fsrv);
+ classified = 1;
+ need_hash = 0;
+
cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
/* Saturated increment */
- if (afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)
+ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
afl->n_fuzz[cksum % N_FUZZ_SIZE]++;
}
@@ -482,7 +493,17 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
/* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */
- new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
+ if (likely(classified)) {
+
+ new_bits = has_new_bits(afl, afl->virgin_bits);
+
+ } else {
+
+ new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
+
+ if (unlikely(new_bits)) { classified = 1; }
+
+ }
if (likely(!new_bits)) {
@@ -491,8 +512,6 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
- classified = new_bits;
-
save_to_queue:
#ifndef SIMPLE_FILES
@@ -550,21 +569,25 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
}
- /* AFLFast schedule? update the new queue entry */
- if (cksum) {
+ if (unlikely(need_hash && new_bits)) {
+
+ /* due to classify counts we have to recalculate the checksum */
+ afl->queue_top->exec_cksum =
+ hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
+ need_hash = 0;
+
+ }
+
+ /* For AFLFast schedules we update the new queue entry */
+ if (likely(cksum)) {
afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
}
- /* due to classify counts we have to recalculate the checksum */
- afl->queue_top->exec_cksum =
- hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
-
/* Try to calibrate inline; this also calls update_bitmap_score() when
successful. */
-
res = calibrate_case(afl, afl->queue_top, mem, afl->queue_cycle - 1, 0);
if (unlikely(res == FSRV_RUN_ERROR)) {
@@ -598,7 +621,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->non_instrumented_mode)) {
- if (!classified) {
+ if (unlikely(!classified)) {
classify_counts(&afl->fsrv);
classified = 1;
@@ -723,7 +746,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
if (likely(!afl->non_instrumented_mode)) {
- if (!classified) { classify_counts(&afl->fsrv); }
+ if (unlikely(!classified)) {
+
+ classify_counts(&afl->fsrv);
+ classified = 1;
+
+ }
simplify_trace(afl, afl->fsrv.trace_bits);
diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c
index d0c829e2..3e6432ca 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -33,15 +33,19 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) {
setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1);
- if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); }
+ if (fsrv->qemu_mode || fsrv->cs_mode) {
+
+ setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0);
+
+ }
if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->cmplog_binary) {
- argv[0] = fsrv->cmplog_binary;
+ fsrv->target_path = argv[0] = fsrv->cmplog_binary;
}
- execv(argv[0], argv);
+ execv(fsrv->target_path, argv);
}
diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c
index 884bb569..f6de11ae 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c
index e41d29fd..bd591c8f 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -24,7 +24,9 @@
*/
#include "afl-fuzz.h"
+#include "common.h"
#include <limits.h>
+#include <string.h>
#include "cmplog.h"
#ifdef HAVE_AFFINITY
@@ -716,10 +718,21 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (nl_cnt) {
- i = nl_cnt;
+ u32 done = 0;
+
+ if (unlikely(afl->in_place_resume)) {
+
+ i = nl_cnt;
+
+ } else {
+
+ i = 0;
+
+ }
+
do {
- --i;
+ if (unlikely(afl->in_place_resume)) { --i; }
struct stat st;
u8 dfn[PATH_MAX];
@@ -743,7 +756,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
free(nl[i]); /* not tracked */
read_testcases(afl, fn2);
ck_free(fn2);
- continue;
+ goto next_entry;
}
@@ -752,7 +765,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
if (!S_ISREG(st.st_mode) || !st.st_size || strstr(fn2, "/README.txt")) {
ck_free(fn2);
- continue;
+ goto next_entry;
}
@@ -799,18 +812,18 @@ void read_testcases(afl_state_t *afl, u8 *directory) {
}
- /*
- if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) {
+ next_entry:
+ if (unlikely(afl->in_place_resume)) {
- u64 cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size,
- HASH_CONST); afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE;
- afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1;
+ if (unlikely(i == 0)) { done = 1; }
- }
+ } else {
+
+ if (unlikely(++i >= (u32)nl_cnt)) { done = 1; }
- */
+ }
- } while (i > 0);
+ } while (!done);
}
@@ -1120,7 +1133,7 @@ void perform_dry_run(afl_state_t *afl) {
}
- if (q->var_behavior) {
+ if (unlikely(q->var_behavior && !afl->afl_env.afl_no_warn_instability)) {
WARNF("Instrumentation output varies across runs.");
@@ -1817,17 +1830,35 @@ static void handle_existing_out_dir(afl_state_t *afl) {
if (afl->file_extension) {
- fn = alloc_printf("%s/.cur_input.%s", afl->tmp_dir, afl->file_extension);
+ fn = alloc_printf("%s/.cur_input.%s", afl->out_dir, afl->file_extension);
} else {
- fn = alloc_printf("%s/.cur_input", afl->tmp_dir);
+ fn = alloc_printf("%s/.cur_input", afl->out_dir);
}
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
+ if (afl->afl_env.afl_tmpdir) {
+
+ if (afl->file_extension) {
+
+ fn = alloc_printf("%s/.cur_input.%s", afl->afl_env.afl_tmpdir,
+ afl->file_extension);
+
+ } else {
+
+ fn = alloc_printf("%s/.cur_input", afl->afl_env.afl_tmpdir);
+
+ }
+
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
+ }
+
fn = alloc_printf("%s/fuzz_bitmap", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
@@ -1848,6 +1879,10 @@ static void handle_existing_out_dir(afl_state_t *afl) {
}
+ fn = alloc_printf("%s/queue_data", afl->out_dir);
+ if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
+ ck_free(fn);
+
fn = alloc_printf("%s/cmdline", afl->out_dir);
if (unlink(fn) && errno != ENOENT) { goto dir_cleanup_failed; }
ck_free(fn);
@@ -2764,7 +2799,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
!afl->fsrv.nyx_mode &&
#endif
!afl->fsrv.cs_mode && !afl->non_instrumented_mode &&
- !memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+ !afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"Looks like the target binary is not instrumented! The fuzzer depends "
@@ -2795,7 +2830,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if ((afl->fsrv.cs_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) &&
- memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
+ afl_memmem(f_data, f_len, SHM_ENV_VAR, strlen(SHM_ENV_VAR) + 1)) {
SAYF("\n" cLRD "[-] " cRST
"This program appears to be instrumented with afl-gcc, but is being "
@@ -2808,9 +2843,9 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
- if (memmem(f_data, f_len, "__asan_init", 11) ||
- memmem(f_data, f_len, "__msan_init", 11) ||
- memmem(f_data, f_len, "__lsan_init", 11)) {
+ if (afl_memmem(f_data, f_len, "__asan_init", 11) ||
+ afl_memmem(f_data, f_len, "__msan_init", 11) ||
+ afl_memmem(f_data, f_len, "__lsan_init", 11)) {
afl->fsrv.uses_asan = 1;
@@ -2818,7 +2853,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
/* Detect persistent & deferred init signatures in the binary. */
- if (memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
+ if (afl_memmem(f_data, f_len, PERSIST_SIG, strlen(PERSIST_SIG) + 1)) {
OKF(cPIN "Persistent mode binary detected.");
setenv(PERSIST_ENV_VAR, "1", 1);
@@ -2845,7 +2880,7 @@ void check_binary(afl_state_t *afl, u8 *fname) {
}
if (afl->fsrv.frida_mode ||
- memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
+ afl_memmem(f_data, f_len, DEFER_SIG, strlen(DEFER_SIG) + 1)) {
OKF(cPIN "Deferred forkserver binary detected.");
setenv(DEFER_ENV_VAR, "1", 1);
@@ -2901,8 +2936,11 @@ void setup_signal_handlers(void) {
struct sigaction sa;
+ memset((void *)&sa, 0, sizeof(sa));
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c
index ef30b993..64dbe7c6 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -179,11 +179,19 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
void *dh;
struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator));
- mutator->name = fn;
- if (memchr(fn, '/', strlen(fn)))
- mutator->name_short = strrchr(fn, '/') + 1;
- else
+ if (memchr(fn, '/', strlen(fn))) {
+
+ mutator->name_short = strdup(strrchr(fn, '/') + 1);
+
+ } else {
+
mutator->name_short = strdup(fn);
+
+ }
+
+ if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; }
+
+ mutator->name = fn;
ACTF("Loading custom mutator library from '%s'...", fn);
dh = dlopen(fn, RTLD_NOW);
@@ -312,12 +320,18 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
if (notrim) {
+ if (mutator->afl_custom_init_trim || mutator->afl_custom_trim ||
+ mutator->afl_custom_post_trim) {
+
+ WARNF(
+ "Custom mutator does not implement all three trim APIs, standard "
+ "trimming will be used.");
+
+ }
+
mutator->afl_custom_init_trim = NULL;
mutator->afl_custom_trim = NULL;
mutator->afl_custom_post_trim = NULL;
- ACTF(
- "Custom mutator does not implement all three trim APIs, standard "
- "trimming will be used.");
}
@@ -358,6 +372,19 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) {
}
+ /* "afl_custom_splice_optout", optional, never called */
+ mutator->afl_custom_splice_optout = dlsym(dh, "afl_custom_splice_optout");
+ if (!mutator->afl_custom_splice_optout) {
+
+ ACTF("optional symbol 'afl_custom_splice_optout' not found.");
+
+ } else {
+
+ OKF("Found 'afl_custom_splice_optout'.");
+ afl->custom_splice_optout = 1;
+
+ }
+
/* "afl_custom_fuzz_send", optional */
mutator->afl_custom_fuzz_send = dlsym(dh, "afl_custom_fuzz_send");
if (!mutator->afl_custom_fuzz_send) {
diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c
index ed9e7a81..ee562f96 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -446,9 +446,12 @@ u8 fuzz_one_original(afl_state_t *afl) {
ACTF(
"Fuzzing test case #%u (%u total, %llu crashes saved, "
- "perf_score=%0.0f, exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
+ "perf_score=%0.0f, weight=%0.0f, favorite=%u, was_fuzzed=%u, "
+ "exec_us=%llu, hits=%u, map=%u, ascii=%u)...",
afl->current_entry, afl->queued_items, afl->saved_crashes,
- afl->queue_cur->perf_score, afl->queue_cur->exec_us,
+ 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);
fflush(stdout);
@@ -561,11 +564,11 @@ u8 fuzz_one_original(afl_state_t *afl) {
} else {
- if (afl->cmplog_lvl == 3 ||
- (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
- afl->queue_cur->favored ||
- !(afl->fsrv.total_execs % afl->queued_items) ||
- get_cur_time() - afl->last_find_time > 300000) { // 300 seconds
+ if (afl->queue_cur->favored || afl->cmplog_lvl == 3 ||
+ (afl->cmplog_lvl == 2 &&
+ (afl->queue_cur->tc_ref ||
+ afl->fsrv.total_execs % afl->queued_items <= 10)) ||
+ get_cur_time() - afl->last_find_time > 250000) { // 250 seconds
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
@@ -584,7 +587,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
if it has gone through deterministic testing in earlier, resumed runs
(passed_det). */
- if (likely(afl->queue_cur->passed_det) || likely(afl->skip_deterministic) ||
+ if (likely(afl->skip_deterministic) || likely(afl->queue_cur->passed_det) ||
likely(perf_score <
(afl->queue_cur->depth * 30 <= afl->havoc_max_mult * 100
? afl->queue_cur->depth * 30
@@ -743,6 +746,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bits. */
@@ -775,6 +781,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Four walking bits. */
@@ -811,6 +820,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Effector map setup. These macros calculate:
@@ -919,6 +931,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bytes. */
@@ -962,6 +977,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_bitflip; }
@@ -1005,6 +1023,9 @@ u8 fuzz_one_original(afl_state_t *afl) {
afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_bitflip:
@@ -1097,6 +1118,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 16-bit arithmetics, both endians. */
@@ -1227,6 +1251,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 32-bit arithmetics, both endians. */
@@ -1356,6 +1383,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_arith:
@@ -1422,6 +1452,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Setting 16-bit integers, both endians. */
@@ -1510,6 +1543,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_interest; }
@@ -1599,6 +1635,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_interest:
@@ -1672,6 +1711,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of user-supplied extras. */
@@ -1728,6 +1770,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_user_extras:
@@ -1786,6 +1831,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of auto extras. */
@@ -1842,6 +1890,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_extras:
@@ -1860,9 +1911,10 @@ custom_mutator_stage:
afl->stage_name = "custom mutator";
afl->stage_short = "custom";
- afl->stage_max = HAVOC_CYCLES * perf_score / afl->havoc_div / 100;
afl->stage_val_type = STAGE_VAL_NONE;
bool has_custom_fuzz = false;
+ u32 shift = unlikely(afl->custom_only) ? 7 : 8;
+ afl->stage_max = (HAVOC_CYCLES * perf_score / afl->havoc_div) >> shift;
if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
@@ -1879,6 +1931,7 @@ custom_mutator_stage:
if (el->afl_custom_fuzz) {
afl->current_custom_fuzz = el;
+ afl->stage_name = el->name_short;
if (el->afl_custom_fuzz_count) {
@@ -1905,7 +1958,8 @@ custom_mutator_stage:
u32 target_len = 0;
/* check if splicing makes sense yet (enough entries) */
- if (likely(afl->ready_for_splicing_count > 1)) {
+ if (likely(!afl->custom_splice_optout &&
+ afl->ready_for_splicing_count > 1)) {
/* Pick a random other queue entry for passing to external API
that has the necessary length */
@@ -1935,7 +1989,8 @@ custom_mutator_stage:
if (unlikely(!mutated_buf)) {
- FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size);
+ // FATAL("Error in custom_fuzz. Size returned: %zu", mutated_size);
+ break;
}
@@ -1987,7 +2042,10 @@ custom_mutator_stage:
new_hit_cnt = afl->queued_items + afl->saved_crashes;
afl->stage_finds[STAGE_CUSTOM_MUTATOR] += new_hit_cnt - orig_hit_cnt;
- afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_max;
+ afl->stage_cycles[STAGE_CUSTOM_MUTATOR] += afl->stage_cur;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (likely(afl->custom_only)) {
@@ -2012,8 +2070,9 @@ havoc_stage:
afl->stage_name = "havoc";
afl->stage_short = "havoc";
- afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
- perf_score / afl->havoc_div / 100;
+ afl->stage_max = ((doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div) >>
+ 8;
} else {
@@ -2022,11 +2081,11 @@ havoc_stage:
snprintf(afl->stage_name_buf, STAGE_BUF_SIZE, "splice %u", splice_cycle);
afl->stage_name = afl->stage_name_buf;
afl->stage_short = "splice";
- afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+ afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8;
}
- if (afl->stage_max < HAVOC_MIN) { afl->stage_max = HAVOC_MIN; }
+ if (unlikely(afl->stage_max < HAVOC_MIN)) { afl->stage_max = HAVOC_MIN; }
temp_len = len;
@@ -2925,11 +2984,17 @@ havoc_stage:
afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
} else {
afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
}
@@ -3411,6 +3476,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP1] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bits. */
@@ -3442,6 +3510,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP2] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP2] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Four walking bits. */
@@ -3477,6 +3548,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP4] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP4] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Effector map setup. These macros calculate:
@@ -3584,6 +3658,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Two walking bytes. */
@@ -3626,6 +3703,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_bitflip; }
@@ -3668,6 +3748,9 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
afl->stage_finds[STAGE_FLIP32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_FLIP32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_bitflip:
@@ -3758,6 +3841,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 16-bit arithmetics, both endians. */
@@ -3884,6 +3970,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* 32-bit arithmetics, both endians. */
@@ -4009,6 +4098,9 @@ skip_bitflip:
afl->stage_finds[STAGE_ARITH32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_ARITH32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_arith:
@@ -4074,6 +4166,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST8] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST8] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Setting 16-bit integers, both endians. */
@@ -4160,6 +4255,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST16] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST16] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
if (len < 4) { goto skip_interest; }
@@ -4247,6 +4345,9 @@ skip_arith:
afl->stage_finds[STAGE_INTEREST32] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_INTEREST32] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_interest:
@@ -4320,6 +4421,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of user-supplied extras. */
@@ -4376,6 +4480,9 @@ skip_interest:
afl->stage_finds[STAGE_EXTRAS_UI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_UI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_user_extras:
@@ -4435,6 +4542,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AO] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AO] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
/* Insertion of auto extras. */
@@ -4491,6 +4601,9 @@ skip_user_extras:
afl->stage_finds[STAGE_EXTRAS_AI] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_EXTRAS_AI] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
skip_extras:
@@ -4516,8 +4629,9 @@ pacemaker_fuzzing:
afl->stage_name = MOpt_globals.havoc_stagename;
afl->stage_short = MOpt_globals.havoc_stagenameshort;
- afl->stage_max = (doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
- perf_score / afl->havoc_div / 100;
+ afl->stage_max = ((doing_det ? HAVOC_CYCLES_INIT : HAVOC_CYCLES) *
+ perf_score / afl->havoc_div) >>
+ 7;
} else {
@@ -4527,7 +4641,7 @@ pacemaker_fuzzing:
MOpt_globals.splice_stageformat, splice_cycle);
afl->stage_name = afl->stage_name_buf;
afl->stage_short = MOpt_globals.splice_stagenameshort;
- afl->stage_max = SPLICE_HAVOC * perf_score / afl->havoc_div / 100;
+ afl->stage_max = (SPLICE_HAVOC * perf_score / afl->havoc_div) >> 8;
}
@@ -5316,11 +5430,17 @@ pacemaker_fuzzing:
afl->stage_finds[STAGE_HAVOC] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_HAVOC] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
} else {
afl->stage_finds[STAGE_SPLICE] += new_hit_cnt - orig_hit_cnt;
afl->stage_cycles[STAGE_SPLICE] += afl->stage_max;
+#ifdef INTROSPECTION
+ afl->queue_cur->stats_mutated += afl->stage_max;
+#endif
}
@@ -5572,6 +5692,7 @@ pacemaker_fuzzing:
} /* block */
+ ++afl->queue_cur->fuzz_level;
return ret_val;
}
@@ -5681,13 +5802,11 @@ void pso_updating(afl_state_t *afl) {
}
-/* larger change for MOpt implementation: the original fuzz_one was renamed
- to fuzz_one_original. All documentation references to fuzz_one therefore
- mean fuzz_one_original */
-
+/* The entry point for the mutator, choosing the default mutator, and/or MOpt
+ depending on the configuration. */
u8 fuzz_one(afl_state_t *afl) {
- int key_val_lv_1 = 0, key_val_lv_2 = 0;
+ int key_val_lv_1 = -1, key_val_lv_2 = -1;
#ifdef _AFL_DOCUMENT_MUTATIONS
@@ -5707,7 +5826,12 @@ u8 fuzz_one(afl_state_t *afl) {
#endif
- // if limit_time_sig == -1 then both are run after each other
+ /*
+ -L command line paramter => limit_time_sig value
+ limit_time_sig == 0 then run the default mutator
+ limit_time_sig > 0 then run MOpt
+ limit_time_sig < 0 both are run
+ */
if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); }
@@ -5729,6 +5853,9 @@ u8 fuzz_one(afl_state_t *afl) {
}
+ if (unlikely(key_val_lv_1 == -1)) { key_val_lv_1 = 0; }
+ if (likely(key_val_lv_2 == -1)) { key_val_lv_2 = 0; }
+
return (key_val_lv_1 | key_val_lv_2);
}
diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c
index d8aed8c6..7dad0770 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -219,11 +219,14 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
if (py_module != NULL) {
- u8 py_notrim = 0, py_idx;
- /* init, required */
+ u8 py_notrim = 0;
py_functions[PY_FUNC_INIT] = PyObject_GetAttrString(py_module, "init");
- if (!py_functions[PY_FUNC_INIT])
- FATAL("init function not found in python module");
+ if (!py_functions[PY_FUNC_INIT]) {
+
+ WARNF("init function not found in python module");
+
+ }
+
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "fuzz");
if (!py_functions[PY_FUNC_FUZZ])
py_functions[PY_FUNC_FUZZ] = PyObject_GetAttrString(py_module, "mutate");
@@ -231,8 +234,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
PyObject_GetAttrString(py_module, "describe");
py_functions[PY_FUNC_FUZZ_COUNT] =
PyObject_GetAttrString(py_module, "fuzz_count");
- if (!py_functions[PY_FUNC_FUZZ])
- WARNF("fuzz function not found in python module");
py_functions[PY_FUNC_POST_PROCESS] =
PyObject_GetAttrString(py_module, "post_process");
py_functions[PY_FUNC_INIT_TRIM] =
@@ -248,6 +249,9 @@ 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_SPLICE_OPTOUT] =
+ PyObject_GetAttrString(py_module, "splice_optout");
+ if (py_functions[PY_FUNC_SPLICE_OPTOUT]) { afl->custom_splice_optout = 1; }
py_functions[PY_FUNC_QUEUE_NEW_ENTRY] =
PyObject_GetAttrString(py_module, "queue_new_entry");
py_functions[PY_FUNC_INTROSPECTION] =
@@ -256,36 +260,6 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) {
if (!py_functions[PY_FUNC_DEINIT])
WARNF("deinit function not found in python module");
- for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) {
-
- if (!py_functions[py_idx] || !PyCallable_Check(py_functions[py_idx])) {
-
- if (py_idx >= PY_FUNC_INIT_TRIM && py_idx <= PY_FUNC_TRIM) {
-
- // Implementing the trim API is optional for now
- if (PyErr_Occurred()) { PyErr_Print(); }
- py_notrim = 1;
-
- } else if (py_idx >= PY_OPTIONAL) {
-
- // Only _init and _deinit are not optional currently
-
- if (PyErr_Occurred()) { PyErr_Print(); }
-
- } else {
-
- fprintf(stderr,
- "Cannot find/call function with index %d in external "
- "Python module.\n",
- py_idx);
- return NULL;
-
- }
-
- }
-
- }
-
if (py_notrim) {
py_functions[PY_FUNC_INIT_TRIM] = NULL;
@@ -338,6 +312,8 @@ static void init_py(afl_state_t *afl, py_mutator_t *py_mutator,
(void)afl;
+ if (py_mutator->py_functions[PY_FUNC_INIT] == NULL) { return; }
+
PyObject *py_args, *py_value;
/* Provide the init function a seed for the Python RNG */
@@ -394,16 +370,34 @@ void deinit_py(void *py_mutator) {
}
+void splice_optout_py(void *py_mutator) {
+
+ // this is never called
+ (void)(py_mutator);
+
+}
+
struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
char *module_name) {
struct custom_mutator *mutator;
mutator = ck_alloc(sizeof(struct custom_mutator));
-
mutator->name = module_name;
ACTF("Loading Python mutator library from '%s'...", module_name);
+ if (memchr(module_name, '/', strlen(module_name))) {
+
+ mutator->name_short = strdup(strrchr(module_name, '/') + 1);
+
+ } else {
+
+ mutator->name_short = strdup(module_name);
+
+ }
+
+ if (strlen(mutator->name_short) > 22) { mutator->name_short[21] = 0; }
+
py_mutator_t *py_mutator;
py_mutator = init_py_module(afl, module_name);
mutator->data = py_mutator;
@@ -474,6 +468,13 @@ struct custom_mutator *load_custom_mutator_py(afl_state_t *afl,
}
+ if (py_functions[PY_FUNC_SPLICE_OPTOUT]) {
+
+ mutator->afl_custom_splice_optout = splice_optout_py;
+ afl->custom_splice_optout = 1;
+
+ }
+
if (py_functions[PY_FUNC_QUEUE_NEW_ENTRY]) {
mutator->afl_custom_queue_new_entry = queue_new_entry_py;
diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c
index d8dbdfbe..8ad7cd97 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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:
@@ -27,6 +27,22 @@
#include <ctype.h>
#include <math.h>
+#ifdef _STANDALONE_MODULE
+void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
+
+ return;
+
+}
+
+void run_afl_custom_queue_new_entry(afl_state_t *afl, struct queue_entry *q,
+ u8 *a, u8 *b) {
+
+ return;
+
+}
+
+#endif
+
/* select next queue entry based on alias algo - fast! */
inline u32 select_next_queue_entry(afl_state_t *afl) {
@@ -51,13 +67,15 @@ double compute_weight(afl_state_t *afl, struct queue_entry *q,
if (likely(afl->schedule >= FAST && afl->schedule <= RARE)) {
u32 hits = afl->n_fuzz[q->n_fuzz_entry];
- if (likely(hits)) { weight *= log10(hits) + 1; }
+ if (likely(hits)) { weight /= (log10(hits) + 1); }
}
if (likely(afl->schedule < RARE)) { weight *= (avg_exec_us / q->exec_us); }
weight *= (log(q->bitmap_size) / avg_bitmap_size);
weight *= (1 + (q->tc_ref / avg_top_size));
+
+ if (unlikely(weight < 0.1)) { weight = 0.1; }
if (unlikely(q->favored)) { weight *= 5; }
if (unlikely(!q->was_fuzzed)) { weight *= 2; }
@@ -77,8 +95,8 @@ void create_alias_table(afl_state_t *afl) {
afl->alias_probability = (double *)afl_realloc(
(void **)&afl->alias_probability, n * sizeof(double));
double *P = (double *)afl_realloc(AFL_BUF_PARAM(out), n * sizeof(double));
- int *S = (u32 *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
- int *L = (u32 *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
+ int *S = (int *)afl_realloc(AFL_BUF_PARAM(out_scratch), n * sizeof(u32));
+ int *L = (int *)afl_realloc(AFL_BUF_PARAM(in_scratch), n * sizeof(u32));
if (!P || !S || !L || !afl->alias_table || !afl->alias_probability) {
@@ -131,6 +149,20 @@ void create_alias_table(afl_state_t *afl) {
}
+ if (unlikely(afl->schedule == MMOPT) && afl->queued_discovered) {
+
+ u32 cnt = afl->queued_discovered >= 5 ? 5 : afl->queued_discovered;
+
+ for (i = n - cnt; i < n; i++) {
+
+ struct queue_entry *q = afl->queue_buf[i];
+
+ if (likely(!q->disabled)) { q->weight *= 2.0; }
+
+ }
+
+ }
+
for (i = 0; i < n; i++) {
// weight is always 0 for disabled entries
@@ -246,11 +278,11 @@ void create_alias_table(afl_state_t *afl) {
void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
- u8 fn[PATH_MAX];
- s32 fd;
+ char fn[PATH_MAX];
+ s32 fd;
snprintf(fn, PATH_MAX, "%s/queue/.state/deterministic_done/%s", afl->out_dir,
- strrchr(q->fname, '/') + 1);
+ strrchr((char *)q->fname, '/') + 1);
fd = open(fn, O_WRONLY | O_CREAT | O_EXCL, DEFAULT_PERMISSION);
if (fd < 0) { PFATAL("Unable to create '%s'", fn); }
@@ -265,10 +297,10 @@ void mark_as_det_done(afl_state_t *afl, struct queue_entry *q) {
void mark_as_variable(afl_state_t *afl, struct queue_entry *q) {
- u8 fn[PATH_MAX];
- u8 ldest[PATH_MAX];
+ char fn[PATH_MAX];
+ char ldest[PATH_MAX];
- u8 *fn_name = strrchr(q->fname, '/') + 1;
+ char *fn_name = strrchr((char *)q->fname, '/') + 1;
sprintf(ldest, "../../%s", fn_name);
sprintf(fn, "%s/queue/.state/variable_behavior/%s", afl->out_dir, fn_name);
@@ -292,12 +324,12 @@ void mark_as_redundant(afl_state_t *afl, struct queue_entry *q, u8 state) {
if (likely(state == q->fs_redundant)) { return; }
- u8 fn[PATH_MAX];
+ char fn[PATH_MAX];
q->fs_redundant = state;
sprintf(fn, "%s/queue/.state/redundant_edges/%s", afl->out_dir,
- strrchr(q->fname, '/') + 1);
+ strrchr((char *)q->fname, '/') + 1);
if (state) {
@@ -408,7 +440,7 @@ u8 check_if_text_buf(u8 *buf, u32 len) {
static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
- if (q->len < AFL_TXT_MIN_LEN) return 0;
+ if (q->len < AFL_TXT_MIN_LEN || q->len < AFL_TXT_MAX_LEN) return 0;
u8 *buf;
int fd;
@@ -416,8 +448,8 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
ssize_t comp;
if (len >= MAX_FILE) len = MAX_FILE - 1;
- if ((fd = open(q->fname, O_RDONLY)) < 0) return 0;
- buf = afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
+ if ((fd = open((char *)q->fname, O_RDONLY)) < 0) return 0;
+ buf = (u8 *)afl_realloc(AFL_BUF_PARAM(in_scratch), len + 1);
comp = read(fd, buf, len);
close(fd);
if (comp != (ssize_t)len) return 0;
@@ -519,7 +551,8 @@ static u8 check_if_text(afl_state_t *afl, struct queue_entry *q) {
void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
- struct queue_entry *q = ck_alloc(sizeof(struct queue_entry));
+ struct queue_entry *q =
+ (struct queue_entry *)ck_alloc(sizeof(struct queue_entry));
q->fname = fname;
q->len = len;
@@ -553,13 +586,30 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
afl->cycles_wo_finds = 0;
- struct queue_entry **queue_buf = afl_realloc(
+ struct queue_entry **queue_buf = (struct queue_entry **)afl_realloc(
AFL_BUF_PARAM(queue), afl->queued_items * sizeof(struct queue_entry *));
if (unlikely(!queue_buf)) { PFATAL("alloc"); }
queue_buf[afl->queued_items - 1] = q;
q->id = afl->queued_items - 1;
- afl->last_find_time = get_cur_time();
+ u64 cur_time = get_cur_time();
+
+ if (likely(afl->start_time) &&
+ unlikely(afl->longest_find_time < cur_time - afl->last_find_time)) {
+
+ if (unlikely(!afl->last_find_time)) {
+
+ afl->longest_find_time = cur_time - afl->start_time;
+
+ } else {
+
+ afl->longest_find_time = cur_time - afl->last_find_time;
+
+ }
+
+ }
+
+ afl->last_find_time = cur_time;
if (afl->custom_mutators_count) {
@@ -573,7 +623,11 @@ void add_to_queue(afl_state_t *afl, u8 *fname, u32 len, u8 passed_det) {
}
/* only redqueen currently uses is_ascii */
- if (afl->shm.cmplog_mode) q->is_ascii = check_if_text(afl, q);
+ if (unlikely(afl->shm.cmplog_mode && !q->is_ascii)) {
+
+ q->is_ascii = check_if_text(afl, q);
+
+ }
}
@@ -703,7 +757,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
if (!q->trace_mini) {
u32 len = (afl->fsrv.map_size >> 3);
- q->trace_mini = ck_alloc(len);
+ q->trace_mini = (u8 *)ck_alloc(len);
minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits);
}
@@ -1006,10 +1060,16 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
break;
case LIN:
+ // Don't modify perf_score for unfuzzed seeds
+ if (!q->fuzz_level) break;
+
factor = q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
break;
case QUAD:
+ // Don't modify perf_score for unfuzzed seeds
+ if (!q->fuzz_level) break;
+
factor =
q->fuzz_level * q->fuzz_level / (afl->n_fuzz[q->n_fuzz_entry] + 1);
break;
@@ -1089,19 +1149,19 @@ inline void queue_testcase_retake(afl_state_t *afl, struct queue_entry *q,
if (len != old_len) {
afl->q_testcase_cache_size = afl->q_testcase_cache_size + len - old_len;
- q->testcase_buf = realloc(q->testcase_buf, len);
+ q->testcase_buf = (u8 *)realloc(q->testcase_buf, len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
}
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
ck_read(fd, q->testcase_buf, len, q->fname);
close(fd);
@@ -1121,7 +1181,7 @@ inline void queue_testcase_retake_mem(afl_state_t *afl, struct queue_entry *q,
if (likely(len != old_len)) {
- u8 *ptr = realloc(q->testcase_buf, len);
+ u8 *ptr = (u8 *)realloc(q->testcase_buf, len);
if (likely(ptr)) {
@@ -1153,23 +1213,23 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
if (unlikely(q == afl->queue_cur)) {
- buf = afl_realloc((void **)&afl->testcase_buf, len);
+ buf = (u8 *)afl_realloc((void **)&afl->testcase_buf, len);
} else {
- buf = afl_realloc((void **)&afl->splicecase_buf, len);
+ buf = (u8 *)afl_realloc((void **)&afl->splicecase_buf, len);
}
if (unlikely(!buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
ck_read(fd, buf, len, q->fname);
close(fd);
@@ -1213,7 +1273,7 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
do_once = 1;
// release unneeded memory
- afl->q_testcase_cache = ck_realloc(
+ afl->q_testcase_cache = (struct queue_entry **)ck_realloc(
afl->q_testcase_cache,
(afl->q_testcase_max_cache_entries + 1) * sizeof(size_t));
@@ -1260,15 +1320,15 @@ inline u8 *queue_testcase_get(afl_state_t *afl, struct queue_entry *q) {
/* Map the test case into memory. */
- int fd = open(q->fname, O_RDONLY);
+ int fd = open((char *)q->fname, O_RDONLY);
- if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", q->fname); }
+ if (unlikely(fd < 0)) { PFATAL("Unable to open '%s'", (char *)q->fname); }
- q->testcase_buf = malloc(len);
+ q->testcase_buf = (u8 *)malloc(len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
@@ -1331,11 +1391,11 @@ inline void queue_testcase_store_mem(afl_state_t *afl, struct queue_entry *q,
/* Map the test case into memory. */
- q->testcase_buf = malloc(len);
+ q->testcase_buf = (u8 *)malloc(len);
if (unlikely(!q->testcase_buf)) {
- PFATAL("Unable to malloc '%s' with len %u", q->fname, len);
+ PFATAL("Unable to malloc '%s' with len %u", (char *)q->fname, len);
}
diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c
index 0dae26a3..6e4a655b 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -1035,7 +1035,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
} else {
- diff = 0;
+ o_diff = 0;
}
@@ -1624,6 +1624,8 @@ static void try_to_add_to_dictN(afl_state_t *afl, u128 v, u8 size) {
}
+ if (cons_0 > 1 || cons_ff > 1) { return; }
+
}
maybe_add_auto(afl, (u8 *)&v + off, size);
diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c
index 7f9c3bf3..ac4fb4a9 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -133,7 +133,24 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
}
- if (new_mem != *mem) { *mem = new_mem; }
+ if (new_mem != *mem && new_mem != NULL && new_size > 0) {
+
+ new_buf = afl_realloc(AFL_BUF_PARAM(out_scratch), new_size);
+ if (unlikely(!new_buf)) { PFATAL("alloc"); }
+ memcpy(new_buf, new_mem, new_size);
+
+ /* if AFL_POST_PROCESS_KEEP_ORIGINAL is set then save the original memory
+ prior post-processing in new_mem to restore it later */
+ if (unlikely(afl->afl_env.afl_post_process_keep_original)) {
+
+ new_mem = *mem;
+
+ }
+
+ *mem = new_buf;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+
+ }
if (unlikely(afl->custom_mutators_count)) {
@@ -154,7 +171,18 @@ write_to_testcase(afl_state_t *afl, void **mem, u32 len, u32 fix) {
/* everything as planned. use the potentially new data. */
afl_fsrv_write_to_testcase(&afl->fsrv, *mem, new_size);
- len = new_size;
+
+ if (likely(!afl->afl_env.afl_post_process_keep_original)) {
+
+ len = new_size;
+
+ } else {
+
+ /* restore the original memory which was saved in new_mem */
+ *mem = new_mem;
+ afl_swap_bufs(AFL_BUF_PARAM(out), AFL_BUF_PARAM(out_scratch));
+
+ }
}
@@ -523,7 +551,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
}
- if (unlikely(!var_detected)) {
+ if (unlikely(!var_detected && !afl->afl_env.afl_no_warn_instability)) {
// note: from_queue seems to only be set during initialization
if (afl->afl_env.afl_no_ui || from_queue) {
diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c
index 8bd465f0..5e736029 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -24,6 +24,7 @@
*/
#include <signal.h>
+#include <limits.h>
#include "afl-fuzz.h"
#include "envs.h"
@@ -100,6 +101,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->hang_tmout = EXEC_TIMEOUT;
afl->exit_on_time = 0;
afl->stats_update_freq = 1;
+ afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000;
afl->stats_avg_exec = 0;
afl->skip_deterministic = 1;
afl->sync_time = SYNC_TIME;
@@ -204,6 +206,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_no_affinity =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_NO_WARN_INSTABILITY",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_no_warn_instability =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_TRY_AFFINITY",
afl_environment_variable_len)) {
@@ -292,6 +301,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_TIMEOUTS",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_ignore_timeouts =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES",
afl_environment_variable_len)) {
@@ -378,6 +394,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
afl->afl_env.afl_statsd =
get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+ } else if (!strncmp(env, "AFL_POST_PROCESS_KEEP_ORIGINAL",
+
+ afl_environment_variable_len)) {
+
+ afl->afl_env.afl_post_process_keep_original =
+ get_afl_env(afl_environment_variables[i]) ? 1 : 0;
+
} else if (!strncmp(env, "AFL_TMPDIR",
afl_environment_variable_len)) {
@@ -551,6 +574,26 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
}
+ } else if (!strncmp(env, "AFL_FUZZER_STATS_UPDATE_INTERVAL",
+
+ afl_environment_variable_len)) {
+
+ u64 stats_update_freq_sec =
+ strtoull(get_afl_env(afl_environment_variables[i]), NULL, 0);
+ if (stats_update_freq_sec >= UINT_MAX ||
+ 0 == stats_update_freq_sec) {
+
+ WARNF(
+ "Incorrect value given to AFL_FUZZER_STATS_UPDATE_INTERVAL, "
+ "using default of %d seconds\n",
+ STATS_UPDATE_SEC);
+
+ } else {
+
+ afl->stats_file_update_freq_msecs = stats_update_freq_sec * 1000;
+
+ }
+
}
} else {
@@ -612,7 +655,15 @@ void read_afl_environment(afl_state_t *afl, char **envp) {
}
- if (afl->afl_env.afl_pizza_mode) { afl->pizza_is_served = 1; }
+ if (afl->afl_env.afl_pizza_mode > 0) {
+
+ afl->pizza_is_served = 1;
+
+ } else if (afl->afl_env.afl_pizza_mode < 0) {
+
+ OKF("Pizza easter egg mode is now disabled.");
+
+ }
if (issue_detected) { sleep(2); }
diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c
index 61956dc3..07157bf7 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -62,7 +62,7 @@ void write_setup_file(afl_state_t *afl, u32 argc, char **argv) {
if (memchr(argv[i], '\'', strlen(argv[i]))) {
#else
- if (index(argv[i], '\'')) {
+ if (strchr(argv[i], '\'')) {
#endif
@@ -251,6 +251,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
"fuzzer_pid : %u\n"
"cycles_done : %llu\n"
"cycles_wo_finds : %llu\n"
+ "time_wo_finds : %llu\n"
"execs_done : %llu\n"
"execs_per_sec : %0.02f\n"
"execs_ps_last_min : %0.02f\n"
@@ -291,6 +292,11 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
(afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
(afl->prev_run_time + cur_time - afl->start_time) / 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) /
@@ -365,6 +371,39 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
}
+#ifdef INTROSPECTION
+void write_queue_stats(afl_state_t *afl) {
+
+ FILE *f;
+ u8 *fn = alloc_printf("%s/queue_data", afl->out_dir);
+ if ((f = fopen(fn, "w")) != NULL) {
+
+ u32 id;
+ fprintf(f,
+ "# filename, length, exec_us, selected, skipped, mutations, finds, "
+ "crashes, timeouts, bitmap_size, perf_score, weight, colorized, "
+ "favored, disabled\n");
+ for (id = 0; id < afl->queued_items; ++id) {
+
+ struct queue_entry *q = afl->queue_buf[id];
+ fprintf(f, "\"%s\",%u,%llu,%u,%u,%llu,%u,%u,%u,%u,%.3f,%.3f,%u,%u,%u\n",
+ q->fname, q->len, q->exec_us, q->stats_selected, q->stats_skipped,
+ q->stats_mutated, q->stats_finds, q->stats_crashes,
+ q->stats_tmouts, q->bitmap_size, q->perf_score, q->weight,
+ q->colorized, q->favored, q->disabled);
+
+ }
+
+ fclose(f);
+
+ }
+
+ ck_free(fn);
+
+}
+
+#endif
+
/* Update the plot file if there is a reason to. */
void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
@@ -578,9 +617,10 @@ void show_stats_normal(afl_state_t *afl) {
/* Roughly every minute, update fuzzer stats and save auto tokens. */
- if (unlikely(!afl->non_instrumented_mode &&
- (afl->force_ui_update ||
- cur_ms - afl->stats_last_stats_ms > STATS_UPDATE_SEC * 1000))) {
+ if (unlikely(
+ !afl->non_instrumented_mode &&
+ (afl->force_ui_update || cur_ms - afl->stats_last_stats_ms >
+ afl->stats_file_update_freq_msecs))) {
afl->stats_last_stats_ms = cur_ms;
write_stats_file(afl, t_bytes, t_byte_ratio, stab_ratio,
@@ -613,6 +653,18 @@ void show_stats_normal(afl_state_t *afl) {
}
+ /* Every now and then, write queue data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_queue_ms > QUEUE_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_queue_ms = cur_ms;
+#ifdef INTROSPECTION
+ write_queue_stats(afl);
+#endif
+
+ }
+
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
@@ -624,9 +676,14 @@ void show_stats_normal(afl_state_t *afl) {
/* AFL_EXIT_ON_TIME. */
- if (unlikely(afl->last_find_time && !afl->non_instrumented_mode &&
- afl->afl_env.afl_exit_on_time &&
- (cur_ms - afl->last_find_time) > afl->exit_on_time)) {
+ /* If no coverage was found yet, check whether run time is greater than
+ * exit_on_time. */
+
+ if (unlikely(!afl->non_instrumented_mode && afl->afl_env.afl_exit_on_time &&
+ ((afl->last_find_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time) ||
+ (!afl->last_find_time &&
+ (cur_ms - afl->start_time) > afl->exit_on_time)))) {
afl->stop_soon = 2;
@@ -696,20 +753,20 @@ void show_stats_normal(afl_state_t *afl) {
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
- afl->crash_mode ? cPIN "peruvian were-rabbit"
- : cYEL "american fuzzy lop",
- si, afl->use_banner, afl->power_name);
+ 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);
} else {
#endif
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
- afl->crash_mode ? cPIN "peruvian were-rabbit"
- : cYEL "american fuzzy lop",
- si, afl->use_banner, afl->power_name);
+ 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);
#ifdef __linux__
@@ -1399,6 +1456,18 @@ void show_stats_pizza(afl_state_t *afl) {
}
+ /* Every now and then, write queue data. */
+
+ if (unlikely(afl->force_ui_update ||
+ cur_ms - afl->stats_last_queue_ms > QUEUE_UPDATE_SEC * 1000)) {
+
+ afl->stats_last_queue_ms = cur_ms;
+#ifdef INTROSPECTION
+ write_queue_stats(afl);
+#endif
+
+ }
+
/* Honor AFL_EXIT_WHEN_DONE and AFL_BENCH_UNTIL_CRASH. */
if (unlikely(!afl->non_instrumented_mode && afl->cycles_wo_finds > 100 &&
@@ -1413,12 +1482,11 @@ void show_stats_pizza(afl_state_t *afl) {
/* If no coverage was found yet, check whether run time is greater than
* exit_on_time. */
- if (unlikely(
- !afl->non_instrumented_mode && afl->afl_env.afl_exit_on_time &&
- ((afl->last_find_time &&
- (cur_ms - afl->last_find_time) > afl->exit_on_time) ||
- (!afl->last_find_time && (afl->prev_run_time + cur_ms -
- afl->start_time) > afl->exit_on_time)))) {
+ if (unlikely(!afl->non_instrumented_mode && afl->afl_env.afl_exit_on_time &&
+ ((afl->last_find_time &&
+ (cur_ms - afl->last_find_time) > afl->exit_on_time) ||
+ (!afl->last_find_time &&
+ (cur_ms - afl->start_time) > afl->exit_on_time)))) {
afl->stop_soon = 2;
@@ -1489,20 +1557,22 @@ void show_stats_pizza(afl_state_t *afl) {
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
- afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
- : cYEL "Mozzarbella Pizzeria management system",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s] - Nyx",
+ afl->crash_mode ? cPIN
+ "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
} else {
#endif
- sprintf(banner + banner_pad,
- "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
- afl->crash_mode ? cPIN "Mozzarbella Pizzeria table booking system"
- : cYEL "Mozzarbella Pizzeria management system",
- si, afl->use_banner, afl->power_name);
+ snprintf(banner + banner_pad, sizeof(banner) - banner_pad,
+ "%s " cLCY VERSION cLBL " {%s} " cLGN "(%s) " cPIN "[%s]",
+ afl->crash_mode ? cPIN
+ "Mozzarbella Pizzeria table booking system"
+ : cYEL "Mozzarbella Pizzeria management system",
+ si, afl->use_banner, afl->power_name);
#ifdef __linux__
@@ -1733,10 +1803,10 @@ void show_stats_pizza(afl_state_t *afl) {
/* Show a warning about slow execution. */
- if (afl->stats_avg_exec < 100) {
+ if (afl->stats_avg_exec < 20) {
sprintf(tmp, "%s/sec (%s)", u_stringify_float(IB(0), afl->stats_avg_exec),
- afl->stats_avg_exec < 20 ? "zzzz..." : "Gennarino is at it again!");
+ "zzzz...");
SAYF(bV bSTOP " pizza making speed : " cLRD
"%-22s ",
diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c
index a81cab7d..71d2afd8 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -165,7 +165,6 @@ static void usage(u8 *argv0, int more_help) {
" pacemaker mode (minutes of no new finds). 0 = "
"immediately,\n"
" -1 = immediately and together with normal mutation.\n"
- " See docs/README.MOpt.md\n"
" -c program - enable CmpLog by specifying a binary compiled for "
"it.\n"
" if using QEMU/FRIDA or the fuzzing target is "
@@ -210,7 +209,8 @@ static void usage(u8 *argv0, int more_help) {
" -b cpu_id - bind the fuzzing process to the specified CPU core "
"(0-...)\n"
" -e ext - file extension for the fuzz test input file (if "
- "needed)\n\n",
+ "needed)\n"
+ "\n",
argv0, EXEC_TIMEOUT, MEM_LIMIT, MAX_FILE, FOREIGN_SYNCS_MAX);
if (more_help > 1) {
@@ -258,8 +258,11 @@ static void usage(u8 *argv0, int more_help) {
"AFL_FORKSRV_INIT_TMOUT: time spent waiting for forkserver during startup (in ms)\n"
"AFL_HANG_TMOUT: override timeout value (in milliseconds)\n"
"AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n"
- "AFL_IGNORE_UNKNOWN_ENVS: don't warn on unknown env vars\n"
"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_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"
@@ -291,6 +294,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_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"
@@ -310,7 +315,9 @@ static void usage(u8 *argv0, int more_help) {
"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_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"
"\n"
);
@@ -323,7 +330,7 @@ static void usage(u8 *argv0, int more_help) {
}
#ifdef USE_PYTHON
- SAYF("Compiled with %s module support, see docs/custom_mutator.md\n",
+ SAYF("Compiled with %s module support, see docs/custom_mutators.md\n",
(char *)PYTHON_VERSION);
#else
SAYF("Compiled without Python module support.\n");
@@ -432,76 +439,13 @@ static void fasan_check_afl_preload(char *afl_preload) {
}
- #ifdef __linux__
- #include <dlfcn.h>
-
-nyx_plugin_handler_t *afl_load_libnyx_plugin(u8 *libnyx_binary) {
-
- void *handle;
- nyx_plugin_handler_t *plugin = calloc(1, sizeof(nyx_plugin_handler_t));
-
- ACTF("Trying to load libnyx.so plugin...");
- handle = dlopen((char *)libnyx_binary, RTLD_NOW);
- if (!handle) { goto fail; }
-
- plugin->nyx_new = dlsym(handle, "nyx_new");
- if (plugin->nyx_new == NULL) { goto fail; }
-
- plugin->nyx_new_parent = dlsym(handle, "nyx_new_parent");
- if (plugin->nyx_new_parent == NULL) { goto fail; }
-
- plugin->nyx_new_child = dlsym(handle, "nyx_new_child");
- if (plugin->nyx_new_child == NULL) { goto fail; }
-
- plugin->nyx_shutdown = dlsym(handle, "nyx_shutdown");
- if (plugin->nyx_shutdown == NULL) { goto fail; }
-
- plugin->nyx_option_set_reload_mode =
- dlsym(handle, "nyx_option_set_reload_mode");
- if (plugin->nyx_option_set_reload_mode == NULL) { goto fail; }
-
- plugin->nyx_option_set_timeout = dlsym(handle, "nyx_option_set_timeout");
- if (plugin->nyx_option_set_timeout == NULL) { goto fail; }
-
- plugin->nyx_option_apply = dlsym(handle, "nyx_option_apply");
- if (plugin->nyx_option_apply == NULL) { goto fail; }
-
- plugin->nyx_set_afl_input = dlsym(handle, "nyx_set_afl_input");
- if (plugin->nyx_set_afl_input == NULL) { goto fail; }
-
- plugin->nyx_exec = dlsym(handle, "nyx_exec");
- if (plugin->nyx_exec == NULL) { goto fail; }
-
- plugin->nyx_get_bitmap_buffer = dlsym(handle, "nyx_get_bitmap_buffer");
- if (plugin->nyx_get_bitmap_buffer == NULL) { goto fail; }
-
- plugin->nyx_get_bitmap_buffer_size =
- dlsym(handle, "nyx_get_bitmap_buffer_size");
- if (plugin->nyx_get_bitmap_buffer_size == NULL) { goto fail; }
-
- plugin->nyx_get_aux_string = dlsym(handle, "nyx_get_aux_string");
- if (plugin->nyx_get_aux_string == NULL) { goto fail; }
-
- OKF("libnyx plugin is ready!");
- return plugin;
-
-fail:
-
- FATAL("failed to load libnyx: %s\n", dlerror());
- free(plugin);
- return NULL;
-
-}
-
- #endif
-
/* Main entry point */
int main(int argc, char **argv_orig, char **envp) {
s32 opt, auto_sync = 0 /*, user_set_cache = 0*/;
u64 prev_queued = 0;
- u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0,
+ u32 sync_interval_cnt = 0, seek_to = 0, show_help = 0, default_output = 1,
map_size = get_map_size();
u8 *extras_dir[4];
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
@@ -802,6 +746,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->fsrv.out_file = ck_strdup(optarg);
afl->fsrv.use_stdin = 0;
+ default_output = 0;
break;
case 'x': /* dictionary */
@@ -1296,6 +1241,13 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (afl->is_main_node == 1 && afl->schedule != FAST &&
+ afl->schedule != EXPLORE) {
+
+ FATAL("-M is compatible only with fast and explore -p power schedules");
+
+ }
+
if (optind == argc || !afl->in_dir || !afl->out_dir || show_help) {
usage(argv[0], show_help);
@@ -1332,8 +1284,7 @@ int main(int argc, char **argv_orig, char **envp) {
"Eißfeldt, Andrea Fioraldi and Dominik Maier");
OKF("afl++ is open source, get it at "
"https://github.com/AFLplusplus/AFLplusplus");
- OKF("NOTE: This is v3.x which changes defaults and behaviours - see "
- "README.md");
+ OKF("NOTE: afl++ >= v3 has changed defaults and behaviours - see README.md");
#ifdef __linux__
if (afl->fsrv.nyx_mode) {
@@ -1344,12 +1295,11 @@ int main(int argc, char **argv_orig, char **envp) {
}
#endif
- if (afl->sync_id && afl->is_main_node &&
- afl->afl_env.afl_custom_mutator_only) {
+ if (!afl->skip_deterministic && afl->afl_env.afl_custom_mutator_only) {
- WARNF(
- "Using -M main node with the AFL_CUSTOM_MUTATOR_ONLY mutator options "
- "will result in no deterministic mutations being done!");
+ FATAL(
+ "Using -D determinstic fuzzing is incompatible with "
+ "AFL_CUSTOM_MUTATOR_ONLY!");
}
@@ -1579,6 +1529,29 @@ int main(int argc, char **argv_orig, char **envp) {
}
+ if (afl->limit_time_sig > 0 && afl->custom_mutators_count) {
+
+ if (afl->custom_only) {
+
+ FATAL("Custom mutators are incompatible with MOpt (-L)");
+
+ }
+
+ u32 custom_fuzz = 0;
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_fuzz) { custom_fuzz = 1; }
+
+ });
+
+ if (custom_fuzz) {
+
+ WARNF("afl_custom_fuzz is incompatible with MOpt (-L)");
+
+ }
+
+ }
+
if (afl->afl_env.afl_max_det_extras) {
s32 max_det_extras = atoi(afl->afl_env.afl_max_det_extras);
@@ -1911,6 +1884,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (aa_loc && !afl->fsrv.out_file) {
afl->fsrv.use_stdin = 0;
+ default_output = 0;
if (afl->file_extension) {
@@ -2080,6 +2054,7 @@ int main(int argc, char **argv_orig, char **envp) {
afl->cmplog_fsrv.qemu_mode = afl->fsrv.qemu_mode;
afl->cmplog_fsrv.frida_mode = afl->fsrv.frida_mode;
afl->cmplog_fsrv.cmplog_binary = afl->cmplog_binary;
+ afl->cmplog_fsrv.target_path = afl->fsrv.target_path;
afl->cmplog_fsrv.init_child_func = cmplog_exec_child;
if ((map_size <= DEFAULT_SHMEM_SIZE ||
@@ -2152,9 +2127,13 @@ int main(int argc, char **argv_orig, char **envp) {
if (afl->fsrv.out_file && afl->fsrv.use_shmem_fuzz) {
+ unlink(afl->fsrv.out_file);
afl->fsrv.out_file = NULL;
afl->fsrv.use_stdin = 0;
- if (!afl->unicorn_mode && !afl->fsrv.use_stdin) {
+ close(afl->fsrv.out_fd);
+ afl->fsrv.out_fd = -1;
+
+ if (!afl->unicorn_mode && !afl->fsrv.use_stdin && !default_output) {
WARNF(
"You specified -f or @@ on the command line but the target harness "
@@ -2211,14 +2190,6 @@ int main(int argc, char **argv_orig, char **envp) {
if (!afl->pending_not_fuzzed || !valid_seeds) {
- #ifdef __linux__
- if (afl->fsrv.nyx_mode) {
-
- afl->fsrv.nyx_handlers->nyx_shutdown(afl->fsrv.nyx_runner);
-
- }
-
- #endif
FATAL("We need at least one valid input seed that does not crash!");
}
@@ -2277,8 +2248,10 @@ int main(int argc, char **argv_orig, char **envp) {
// real start time, we reset, so this works correctly with -V
afl->start_time = get_cur_time();
- u32 runs_in_current_cycle = (u32)-1;
- u32 prev_queued_items = 0;
+ #ifdef INTROSPECTION
+ u32 prev_saved_crashes = 0, prev_saved_tmouts = 0;
+ #endif
+ u32 prev_queued_items = 0, runs_in_current_cycle = (u32)-1;
u8 skipped_fuzz;
#ifdef INTROSPECTION
@@ -2306,6 +2279,12 @@ int main(int argc, char **argv_orig, char **envp) {
(!afl->queue_cycle && afl->afl_env.afl_import_first)) &&
afl->sync_id)) {
+ if (!afl->queue_cycle && afl->afl_env.afl_import_first) {
+
+ OKF("Syncing queues from other fuzzer instances first ...");
+
+ }
+
sync_fuzzers(afl);
}
@@ -2449,10 +2428,22 @@ int main(int argc, char **argv_orig, char **envp) {
}
#ifdef INTROSPECTION
- fprintf(afl->introspection_file,
- "CYCLE cycle=%llu cycle_wo_finds=%llu expand_havoc=%u queue=%u\n",
- afl->queue_cycle, afl->cycles_wo_finds, afl->expand_havoc,
- afl->queued_items);
+ {
+
+ u64 cur_time = get_cur_time();
+ fprintf(afl->introspection_file,
+ "CYCLE cycle=%llu cycle_wo_finds=%llu time_wo_finds=%llu "
+ "expand_havoc=%u queue=%u\n",
+ afl->queue_cycle, 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->expand_havoc, afl->queued_items);
+
+ }
+
#endif
if (afl->cycle_schedules) {
@@ -2523,27 +2514,70 @@ int main(int argc, char **argv_orig, char **envp) {
}
- afl->current_entry = select_next_queue_entry(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];
}
skipped_fuzz = fuzz_one(afl);
+ #ifdef INTROSPECTION
+ ++afl->queue_cur->stats_selected;
+
+ if (unlikely(skipped_fuzz)) {
+
+ ++afl->queue_cur->stats_skipped;
+
+ } else {
+
+ if (unlikely(afl->queued_items > prev_queued_items)) {
+
+ afl->queue_cur->stats_finds += afl->queued_items - prev_queued_items;
+ prev_queued_items = afl->queued_items;
+
+ }
+
+ if (unlikely(afl->saved_crashes > prev_saved_crashes)) {
+
+ afl->queue_cur->stats_crashes +=
+ afl->saved_crashes - prev_saved_crashes;
+ prev_saved_crashes = afl->saved_crashes;
+
+ }
+
+ if (unlikely(afl->saved_tmouts > prev_saved_tmouts)) {
+
+ afl->queue_cur->stats_tmouts += afl->saved_tmouts - prev_saved_tmouts;
+ prev_saved_tmouts = afl->saved_tmouts;
+
+ }
+
+ }
+
+ #endif
if (unlikely(!afl->stop_soon && exit_1)) { afl->stop_soon = 2; }
if (unlikely(afl->old_seed_selection)) {
while (++afl->current_entry < afl->queued_items &&
- afl->queue_buf[afl->current_entry]->disabled)
- ;
+ afl->queue_buf[afl->current_entry]->disabled) {};
if (unlikely(afl->current_entry >= afl->queued_items ||
afl->queue_buf[afl->current_entry] == NULL ||
- afl->queue_buf[afl->current_entry]->disabled))
+ afl->queue_buf[afl->current_entry]->disabled)) {
+
afl->queue_cur = NULL;
- else
+
+ } else {
+
afl->queue_cur = afl->queue_buf[afl->current_entry];
+ }
+
}
} while (skipped_fuzz && afl->queue_cur && !afl->stop_soon);
diff --git a/src/afl-gotcpu.c b/src/afl-gotcpu.c
index eee642fb..4f851099 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -92,7 +92,7 @@ static u32 measure_preemption(u32 target_ms) {
volatile u32 v1, v2 = 0;
u64 st_t, en_t, st_c, en_c, real_delta, slice_delta;
- s32 loop_repeats = 0;
+ // s32 loop_repeats = 0;
st_t = get_cur_time_us();
st_c = get_cpu_usage_us();
@@ -113,7 +113,7 @@ repeat_loop:
if (en_t - st_t < target_ms * 1000) {
- loop_repeats++;
+ // loop_repeats++;
goto repeat_loop;
}
@@ -174,7 +174,12 @@ int main(int argc, char **argv) {
if (c == NULL) PFATAL("cpuset_create failed");
cpuset_set(i, c);
- #elif defined(__APPLE__)
+ #elif defined(__APPLE__) && defined(__x86_64__)
+ // the api is not workable on arm64, core's principle
+ // differs significantly hive of core per type vs individual ones.
+ // Possible TODO: For arm64 is to slightly change the meaning
+ // of gotcpu since it makes no sense on this platform
+ // but rather just displaying current policy ?
thread_affinity_policy_data_t c = {i};
thread_port_t native_thread = pthread_mach_thread_np(pthread_self());
if (thread_policy_set(native_thread, THREAD_AFFINITY_POLICY,
@@ -209,7 +214,13 @@ int main(int argc, char **argv) {
#if defined(__linux__)
if (sched_setaffinity(0, sizeof(c), &c)) {
- PFATAL("sched_setaffinity failed for cpu %d", i);
+ const char *error_code = "Unkown error code";
+ if (errno == EFAULT) error_code = "EFAULT";
+ if (errno == EINVAL) error_code = "EINVAL";
+ if (errno == EPERM) error_code = "EPERM";
+ if (errno == ESRCH) error_code = "ESRCH";
+
+ PFATAL("sched_setaffinity failed for cpu %d, error: %s", i, error_code);
}
diff --git a/src/afl-ld-lto.c b/src/afl-ld-lto.c
index 5797def8..5438bd9f 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c
index b48c6fb3..a2c81586 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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 93339a8f..d0e01cb1 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -30,8 +30,10 @@
*/
#define AFL_MAIN
+#define AFL_SHOWMAP
#include "config.h"
+#include "afl-fuzz.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
@@ -62,10 +64,14 @@
#include <sys/types.h>
#include <sys/resource.h>
+static afl_state_t *afl;
+
static char *stdin_file; /* stdin file */
static u8 *in_dir = NULL, /* input folder */
- *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */
+ *out_file = NULL, /* output file or directory */
+ *at_file = NULL, /* Substitution string for @@ */
+ *in_filelist = NULL; /* input file list */
static u8 outfile[PATH_MAX];
@@ -136,7 +142,39 @@ static void kill_child() {
}
-static void classify_counts(afl_forkserver_t *fsrv) {
+/* dummy functions */
+u32 write_to_testcase(afl_state_t *afl, void **mem, u32 a, u32 b) {
+
+ (void)afl;
+ (void)mem;
+ return a + b;
+
+}
+
+void show_stats(afl_state_t *afl) {
+
+ (void)afl;
+
+}
+
+void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
+
+ (void)afl;
+ (void)q;
+
+}
+
+fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv,
+ u32 i) {
+
+ (void)afl;
+ (void)fsrv;
+ (void)i;
+ return 0;
+
+}
+
+void classify_counts(afl_forkserver_t *fsrv) {
u8 *mem = fsrv->trace_bits;
const u8 *map = binary_mode ? count_class_binary : count_class_human;
@@ -308,12 +346,73 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) {
}
+void pre_afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *mem, u32 len) {
+
+ static u8 buf[MAX_FILE];
+ u32 sent = 0;
+
+ if (unlikely(afl->custom_mutators_count)) {
+
+ ssize_t new_size = len;
+ u8 *new_mem = mem;
+ u8 *new_buf = NULL;
+
+ LIST_FOREACH(&afl->custom_mutator_list, struct custom_mutator, {
+
+ if (el->afl_custom_post_process) {
+
+ new_size =
+ el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf);
+
+ if (unlikely(!new_buf || new_size <= 0)) {
+
+ return;
+
+ } else {
+
+ new_mem = new_buf;
+ len = new_size;
+
+ }
+
+ }
+
+ });
+
+ if (new_mem != mem && new_mem != NULL) {
+
+ mem = buf;
+ memcpy(mem, new_mem, new_size);
+
+ }
+
+ 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)) { afl_fsrv_write_to_testcase(fsrv, mem, len); }
+
+}
+
/* Execute target application. */
static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem,
u32 len) {
- afl_fsrv_write_to_testcase(fsrv, mem, len);
+ pre_afl_fsrv_write_to_testcase(fsrv, mem, len);
if (!quiet_mode) { SAYF("-- Program output begins --\n" cRST); }
@@ -434,6 +533,23 @@ static u32 read_file(u8 *in_file) {
}
+#ifdef __linux__
+/* Execute the target application with an empty input (in Nyx mode). */
+static void showmap_run_target_nyx_mode(afl_forkserver_t *fsrv) {
+
+ afl_fsrv_write_to_testcase(fsrv, NULL, 0);
+
+ if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, &stop_soon) ==
+ FSRV_RUN_ERROR) {
+
+ FATAL("Error running target in Nyx mode");
+
+ }
+
+}
+
+#endif
+
/* Execute target application. */
static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) {
@@ -597,49 +713,8 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
char *afl_preload;
char *frida_afl_preload = NULL;
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
+
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -695,7 +770,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -801,6 +880,103 @@ u32 execute_testcases(u8 *dir) {
}
+u32 execute_testcases_filelist(u8 *fn) {
+
+ u32 done = 0;
+ u8 buf[4096];
+ u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX];
+ FILE *f;
+
+ if (!be_quiet) { ACTF("Reading from '%s'...", fn); }
+
+ if ((f = fopen(fn, "r")) == NULL) { FATAL("could not open '%s'", fn); }
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+
+ struct stat st;
+ u8 *fn2 = buf, *fn3;
+
+ while (*fn2 == ' ') {
+
+ ++fn2;
+
+ }
+
+ while (*fn2 &&
+ (fn2[strlen(fn2) - 1] == '\r' || fn2[strlen(fn2) - 1] == '\n' ||
+ fn2[strlen(fn2) - 1] == ' ')) {
+
+ fn2[strlen(fn2) - 1] = 0;
+
+ }
+
+ if (debug) { printf("Getting coverage for '%s'\n", fn2); }
+
+ if (!*fn2) { continue; }
+
+ if (lstat(fn2, &st) || access(fn2, R_OK)) {
+
+ WARNF("Unable to access '%s'", fn2);
+ continue;
+
+ }
+
+ ++done;
+
+ if (!S_ISREG(st.st_mode) || !st.st_size) { continue; }
+
+ if ((fn3 = strrchr(fn2, '/'))) {
+
+ ++fn3;
+
+ } else {
+
+ fn3 = fn2;
+
+ }
+
+ if (st.st_size > MAX_FILE && !be_quiet && !quiet_mode) {
+
+ WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2,
+ stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size),
+ stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE));
+
+ }
+
+ if (!collect_coverage) {
+
+ snprintf(outfile, sizeof(outfile), "%s/%s", out_file, fn3);
+
+ }
+
+ if (read_file(fn2)) {
+
+ if (wait_for_gdb) {
+
+ fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid);
+ fprintf(stderr, "exec: kill -CONT %d\n", getpid());
+ kill(0, SIGSTOP);
+
+ }
+
+ showmap_run_target_forkserver(fsrv, in_data, in_len);
+ ck_free(in_data);
+
+ if (child_crashed && debug) { WARNF("crashed: %s", fn2); }
+
+ if (collect_coverage)
+ analyze_results(fsrv);
+ else
+ tcnt = write_results_to_file(fsrv, outfile);
+
+ }
+
+ }
+
+ return done;
+
+}
+
/* Show banner. */
static void show_banner(void) {
@@ -834,6 +1010,7 @@ static void usage(u8 *argv0) {
" -W - use qemu-based instrumentation with Wine (Wine mode)\n"
" (Not necessary, here for consistency with other afl-* "
"tools)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
"Other settings:\n"
@@ -842,6 +1019,7 @@ static void usage(u8 *argv0) {
" With -C, -o is a file, without -C it must be a "
"directory\n"
" and each bitmap will be written there individually.\n"
+ " -I filelist - alternatively to -i, -I is a list of files\n"
" -C - collect coverage, writes all edges to -o and gives a "
"summary\n"
" Must be combined with -i.\n"
@@ -854,6 +1032,10 @@ static void usage(u8 *argv0) {
"This tool displays raw tuple data captured by AFL instrumentation.\n"
"For additional help, consult %s/README.md.\n\n"
+ "If you use -i/-I mode, then custom mutator post_process send send "
+ "functionality\n"
+ "is supported.\n\n"
+
"Environment variables used:\n"
"LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n"
"AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing "
@@ -912,7 +1094,7 @@ int main(int argc, char **argv_orig, char **envp) {
if (getenv("AFL_QUIET") != NULL) { be_quiet = true; }
- while ((opt = getopt(argc, argv, "+i:o:f:m:t:AeqCZOH:QUWbcrsh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:I:o:f:m:t:AeqCZOH:QUWbcrshXY")) > 0) {
switch (opt) {
@@ -930,6 +1112,11 @@ int main(int argc, char **argv_orig, char **envp) {
in_dir = optarg;
break;
+ case 'I':
+ if (in_filelist) { FATAL("Multiple -I options not supported"); }
+ in_filelist = optarg;
+ break;
+
case 'o':
if (out_file) { FATAL("Multiple -o options not supported"); }
@@ -1100,6 +1287,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv->nyx_mode = 1;
+ fsrv->nyx_parent = true;
+ fsrv->nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'b':
/* Secret undocumented mode. Writes output in raw binary format
@@ -1135,10 +1339,12 @@ int main(int argc, char **argv_orig, char **envp) {
if (optind == argc || !out_file) { usage(argv[0]); }
- if (in_dir) {
+ if (in_dir && in_filelist) { FATAL("you can only specify either -i or -I"); }
+
+ if (in_dir || in_filelist) {
if (!out_file && !collect_coverage)
- FATAL("for -i you need to specify either -C and/or -o");
+ FATAL("for -i/-I you need to specify either -C and/or -o");
}
@@ -1171,7 +1377,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(fsrv, argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+ fsrv->target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv->target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv->target_path = find_binary(argv[optind]);
+#endif
+
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
if (!quiet_mode) {
@@ -1181,7 +1401,7 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (in_dir) {
+ if (in_dir || in_filelist) {
/* If we don't have a file name chosen yet, use a safe default. */
u8 *use_dir = ".";
@@ -1227,13 +1447,75 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv =
get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv->nyx_mode) {
+
+ use_argv = ck_alloc(sizeof(char *) * (1));
+ use_argv[0] = argv[0];
+
+ fsrv->nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(use_argv[0], "libnyx.so");
+ fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv->nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv->nyx_use_tmp_workdir = true;
+ fsrv->nyx_bind_cpu_id = 0;
+#endif
+
} else {
use_argv = argv + optind;
}
+ afl = calloc(1, sizeof(afl_state_t));
+
+ if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
+
+ s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
+ if (forksrv_init_tmout < 1) {
+
+ FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
+
+ }
+
+ fsrv->init_tmout = (u32)forksrv_init_tmout;
+
+ }
+
+ if (getenv("AFL_CRASH_EXITCODE")) {
+
+ long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
+ if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
+ exitcode < -127 || exitcode > 128) {
+
+ FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
+ getenv("AFL_CRASH_EXITCODE"));
+
+ }
+
+ fsrv->uses_crash_exitcode = true;
+ // WEXITSTATUS is 8 bit unsigned
+ fsrv->crash_exitcode = (u8)exitcode;
+
+ }
+
+#ifdef __linux__
+ if (!fsrv->nyx_mode && (in_dir || in_filelist)) {
+
+ (void)check_binary_signatures(fsrv->target_path);
+
+ }
+
+#else
if (in_dir) { (void)check_binary_signatures(fsrv->target_path); }
+#endif
shm_fuzz = ck_alloc(sizeof(sharedmem_t));
@@ -1253,6 +1535,15 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->shmem_fuzz_len = (u32 *)map;
fsrv->shmem_fuzz = map + sizeof(u32);
+ configure_afl_kill_signals(fsrv, NULL, NULL,
+ (fsrv->qemu_mode || unicorn_mode
+#ifdef __linux__
+ || fsrv->nyx_mode
+#endif
+ )
+ ? SIGKILL
+ : SIGTERM);
+
if (!fsrv->cs_mode && !fsrv->qemu_mode && !unicorn_mode) {
u32 save_be_quiet = be_quiet;
@@ -1275,10 +1566,6 @@ int main(int argc, char **argv_orig, char **envp) {
: 0);
be_quiet = save_be_quiet;
- configure_afl_kill_signals(
- fsrv, NULL, NULL,
- (fsrv->qemu_mode || unicorn_mode) ? SIGKILL : SIGTERM);
-
if (new_map_size) {
// only reinitialize when it makes sense
@@ -1303,26 +1590,59 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (in_dir) {
+ if (in_dir || in_filelist) {
+
+ afl->fsrv.dev_urandom_fd = open("/dev/urandom", O_RDONLY);
+ afl->afl_env.afl_custom_mutator_library =
+ getenv("AFL_CUSTOM_MUTATOR_LIBRARY");
+ afl->afl_env.afl_python_module = getenv("AFL_PYTHON_MODULE");
+ setup_custom_mutators(afl);
+
+ } else {
+
+ if (getenv("AFL_CUSTOM_MUTATOR_LIBRARY") || getenv("AFL_PYTHON_MODULE")) {
+
+ WARNF(
+ "Custom mutator environment detected, this is only supported in "
+ "-i/-I mode!\n");
+
+ }
+
+ }
+
+ if (in_dir || in_filelist) {
DIR *dir_in, *dir_out = NULL;
+ u8 *dn = NULL;
if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true;
fsrv->dev_null_fd = open("/dev/null", O_RDWR);
if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); }
- // if a queue subdirectory exists switch to that
- u8 *dn = alloc_printf("%s/queue", in_dir);
- if ((dir_in = opendir(dn)) != NULL) {
+ if (in_filelist) {
+
+ if (!be_quiet) ACTF("Reading from file list '%s'...", in_filelist);
+
+ } else {
+
+ // if a queue subdirectory exists switch to that
+ dn = alloc_printf("%s/queue", in_dir);
+
+ if ((dir_in = opendir(dn)) != NULL) {
+
+ closedir(dir_in);
+ in_dir = dn;
- closedir(dir_in);
- in_dir = dn;
+ } else {
+
+ ck_free(dn);
+
+ }
- } else
+ if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
- ck_free(dn);
- if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir);
+ }
if (!collect_coverage) {
@@ -1365,36 +1685,6 @@ int main(int argc, char **argv_orig, char **envp) {
}
- if (getenv("AFL_FORKSRV_INIT_TMOUT")) {
-
- s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT"));
- if (forksrv_init_tmout < 1) {
-
- FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT");
-
- }
-
- fsrv->init_tmout = (u32)forksrv_init_tmout;
-
- }
-
- if (getenv("AFL_CRASH_EXITCODE")) {
-
- long exitcode = strtol(getenv("AFL_CRASH_EXITCODE"), NULL, 10);
- if ((!exitcode && (errno == EINVAL || errno == ERANGE)) ||
- exitcode < -127 || exitcode > 128) {
-
- FATAL("Invalid crash exitcode, expected -127 to 128, but got %s",
- getenv("AFL_CRASH_EXITCODE"));
-
- }
-
- fsrv->uses_crash_exitcode = true;
- // WEXITSTATUS is 8 bit unsigned
- fsrv->crash_exitcode = (u8)exitcode;
-
- }
-
afl_fsrv_start(fsrv, use_argv, &stop_soon,
(get_afl_env("AFL_DEBUG_CHILD") ||
get_afl_env("AFL_DEBUG_CHILD_OUTPUT"))
@@ -1406,9 +1696,21 @@ int main(int argc, char **argv_orig, char **envp) {
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
- if (execute_testcases(in_dir) == 0) {
+ if (in_dir) {
+
+ if (execute_testcases(in_dir) == 0) {
- FATAL("could not read input testcases from %s", in_dir);
+ FATAL("could not read input testcases from %s", in_dir);
+
+ }
+
+ } else {
+
+ if (execute_testcases_filelist(in_filelist) == 0) {
+
+ FATAL("could not read input testcases from %s", in_filelist);
+
+ }
}
@@ -1428,7 +1730,20 @@ int main(int argc, char **argv_orig, char **envp) {
if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz)
shm_fuzz = deinit_shmem(fsrv, shm_fuzz);
- showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+#endif
+ showmap_run_target(fsrv, use_argv);
+#ifdef __linux__
+
+ } else {
+
+ showmap_run_target_nyx_mode(fsrv);
+
+ }
+
+#endif
tcnt = write_results_to_file(fsrv, out_file);
if (!quiet_mode) {
diff --git a/src/afl-tmin.c b/src/afl-tmin.c
index d93b9a41..e7442d1d 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-2022 AFLplusplus Project. All rights reserved.
+ Copyright 2019-2023 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.
@@ -674,27 +674,6 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
/* Set sane defaults... */
- x = get_afl_env("ASAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "abort_on_error=1")) {
-
- FATAL("Custom ASAN_OPTIONS set without abort_on_error=1 - please fix!");
-
- }
-
-#ifndef ASAN_BUILD
- if (!getenv("AFL_DEBUG") && !strstr(x, "symbolize=0")) {
-
- FATAL("Custom ASAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
-#endif
-
- }
-
x = get_afl_env("MSAN_OPTIONS");
if (x) {
@@ -706,69 +685,9 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) {
}
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom MSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
}
- x = get_afl_env("LSAN_OPTIONS");
-
- if (x) {
-
- if (!strstr(x, "symbolize=0")) {
-
- FATAL("Custom LSAN_OPTIONS set without symbolize=0 - please fix!");
-
- }
-
- }
-
- setenv("ASAN_OPTIONS",
- "abort_on_error=1:"
- "detect_leaks=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "detect_odr_violation=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("UBSAN_OPTIONS",
- "halt_on_error=1:"
- "abort_on_error=1:"
- "malloc_context_size=0:"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0",
- 0);
-
- setenv("MSAN_OPTIONS", "exit_code=" STRINGIFY(MSAN_ERROR) ":"
- "abort_on_error=1:"
- "msan_track_origins=0"
- "allocator_may_return_null=1:"
- "symbolize=0:"
- "handle_segv=0:"
- "handle_sigbus=0:"
- "handle_abort=0:"
- "handle_sigfpe=0:"
- "handle_sigill=0", 0);
-
- setenv("LSAN_OPTIONS",
- "exitcode=" STRINGIFY(LSAN_ERROR) ":"
- "fast_unwind_on_malloc=0:"
- "symbolize=0:"
- "print_suppressions=0",
- 0);
+ set_sanitizer_defaults();
if (get_afl_env("AFL_PRELOAD")) {
@@ -824,7 +743,11 @@ static void setup_signal_handlers(void) {
struct sigaction sa;
sa.sa_handler = NULL;
+#ifdef SA_RESTART
sa.sa_flags = SA_RESTART;
+#else
+ sa.sa_flags = 0;
+#endif
sa.sa_sigaction = NULL;
sigemptyset(&sa.sa_mask);
@@ -866,6 +789,7 @@ static void usage(u8 *argv0) {
"mode)\n"
" (Not necessary, here for consistency with other afl-* "
"tools)\n"
+ " -X - use Nyx mode\n"
#endif
"\n"
@@ -922,7 +846,7 @@ int main(int argc, char **argv_orig, char **envp) {
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
- while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWHh")) > 0) {
+ while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeAOQUWXYHh")) > 0) {
switch (opt) {
@@ -1080,6 +1004,23 @@ int main(int argc, char **argv_orig, char **envp) {
break;
+ case 'Y': // fallthough
+#ifdef __linux__
+ case 'X': /* NYX mode */
+
+ if (fsrv->nyx_mode) { FATAL("Multiple -X options not supported"); }
+
+ fsrv->nyx_mode = 1;
+ fsrv->nyx_parent = true;
+ fsrv->nyx_standalone = true;
+
+ break;
+#else
+ case 'X':
+ FATAL("Nyx mode is only availabe on linux...");
+ break;
+#endif
+
case 'H': /* Hang Mode */
/* Minimizes a testcase to the minimum that still times out */
@@ -1145,7 +1086,21 @@ int main(int argc, char **argv_orig, char **envp) {
set_up_environment(fsrv, argv);
+#ifdef __linux__
+ if (!fsrv->nyx_mode) {
+
+ fsrv->target_path = find_binary(argv[optind]);
+
+ } else {
+
+ fsrv->target_path = ck_strdup(argv[optind]);
+
+ }
+
+#else
fsrv->target_path = find_binary(argv[optind]);
+#endif
+
fsrv->trace_bits = afl_shm_init(&shm, map_size, 0);
detect_file_args(argv + optind, out_file, &fsrv->use_stdin);
signal(SIGALRM, kill_child);
@@ -1169,6 +1124,26 @@ int main(int argc, char **argv_orig, char **envp) {
use_argv =
get_cs_argv(argv[0], &fsrv->target_path, argc - optind, argv + optind);
+#ifdef __linux__
+
+ } else if (fsrv->nyx_mode) {
+
+ fsrv->nyx_id = 0;
+
+ u8 *libnyx_binary = find_afl_binary(argv[0], "libnyx.so");
+ fsrv->nyx_handlers = afl_load_libnyx_plugin(libnyx_binary);
+ if (fsrv->nyx_handlers == NULL) {
+
+ FATAL("failed to initialize libnyx.so...");
+
+ }
+
+ fsrv->nyx_use_tmp_workdir = true;
+ fsrv->nyx_bind_cpu_id = 0;
+
+ use_argv = argv + optind;
+#endif
+
} else {
use_argv = argv + optind;
@@ -1238,7 +1213,12 @@ int main(int argc, char **argv_orig, char **envp) {
fsrv->shmem_fuzz = map + sizeof(u32);
read_initial_file();
+
+#ifdef __linux__
+ if (!fsrv->nyx_mode) { (void)check_binary_signatures(fsrv->target_path); }
+#else
(void)check_binary_signatures(fsrv->target_path);
+#endif
if (!fsrv->qemu_mode && !unicorn_mode) {