From 7a6867e2f8e8b698c08366f79d0c8751b09ce431 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 12 Aug 2020 16:06:30 +0200 Subject: split up __afl_manual_init, added internal AFL_DISABLE_LLVM_INSTRUMENTATION, skipping ctor+ifunc functions for all llvm, code-format --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index edcdac58..1c5b3f4a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,9 +29,9 @@ sending a mail to . - added neverzero counting to trace-pc/pcgard - fixes for laf-intel float splitting (thanks to mark-griffin for reporting) + - skipping ctors and ifuncs for instrumentation - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR for a fixed map address (eg. 0x10000) - - LTO: skipping ctors and ifuncs in fix map address instrumentation - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better -- cgit 1.4.1 From 2c5e103278c3266c15226f097e8e9e15267c57d6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 13 Aug 2020 12:39:18 +0200 Subject: make cmplog deterministic --- docs/Changelog.md | 2 +- src/afl-fuzz-redqueen.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 1c5b3f4a..45d640ea 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,7 +19,7 @@ sending a mail to . - eliminated CPU affinity race condition for -S/-M runs - expanded havoc mode added, on no cycle finds add extra splicing and MOpt into the mix - - fixed a bug in redqueen for strings + - fixed a bug in redqueen for strings and made deterministic with -s - llvm_mode: - now supports llvm 12! - support for AFL_LLVM_ALLOWLIST/AFL_LLVM_DENYLIST (previous diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 9716be95..4309098a 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -151,7 +151,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 exec_cksum) { /* Discard if the mutations change the paths or if it is too decremental in speed */ if (cksum != exec_cksum || - (stop_us - start_us > 2 * afl->queue_cur->exec_us)) { + (stop_us - start_us > 2 * afl->queue_cur->exec_us) && likely(!afl->fixed_seed)) { ranges = add_range(ranges, rng->start, rng->start + s / 2); ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); -- cgit 1.4.1 From 212bb990b7579831baad70735b767dbaf89e9e89 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 13 Aug 2020 21:27:11 +0200 Subject: LTO: apply laf-intel+redqueen/cmplog at link time --- GNUmakefile | 9 ++- README.md | 27 ++++++--- TODO.md | 1 - docs/Changelog.md | 2 + llvm_mode/afl-clang-fast.c | 104 +++++++++++++++++++++++---------- llvm_mode/cmplog-instructions-pass.cc | 4 ++ llvm_mode/cmplog-routines-pass.cc | 4 ++ llvm_mode/compare-transform-pass.so.cc | 3 + llvm_mode/split-compares-pass.so.cc | 4 ++ llvm_mode/split-switches-pass.so.cc | 4 ++ src/afl-showmap.c | 104 ++++++++++++++++++++++++++++----- 11 files changed, 213 insertions(+), 53 deletions(-) (limited to 'docs') diff --git a/GNUmakefile b/GNUmakefile index fe5f8c03..f9020a90 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -97,7 +97,13 @@ ifneq "$(shell uname -m)" "x86_64" endif endif -CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) +ifdef DEBUG + $(info Compiling DEBUG version of binaries) + CFLAGS += -ggdb3 -O0 -Wall -Wextra -Werror +else + CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) +endif + override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \ -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" @@ -305,6 +311,7 @@ help: @echo "==========================================" @echo STATIC - compile AFL++ static @echo ASAN_BUILD - compiles with memory sanitizer for debug purposes + @echo DEBUG - no optimization, -ggdb3, all warnings and -Werror @echo PROFILING - compile afl-fuzz with profiling information @echo AFL_NO_X86 - if compiling on non-intel/amd platforms @echo "==========================================" diff --git a/README.md b/README.md index 18983832..97c0a0d7 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ These build options exist: * STATIC - compile AFL++ static * ASAN_BUILD - compiles with memory sanitizer for debug purposes +* DEBUG - no optimization, -ggdb3, all warnings and -Werror * PROFILING - compile with profiling information (gprof) * NO_PYTHON - disable python support * AFL_NO_X86 - if compiling on non-intel/amd platforms @@ -509,8 +510,8 @@ fuzz your target. On the same machine - due to the design of how afl++ works - there is a maximum number of CPU cores/threads that are useful, use more and the overall performance -degrades instead. This value depends on the target and the limit is between 48 -and 96 cores/threads per machine. +degrades instead. This value depends on the target, and the limit is between 32 +and 64 cores/threads per machine. There should be one main fuzzer (`-M main` option) and as many secondary fuzzers (eg `-S variant1`) as you have cores that you use. @@ -562,11 +563,18 @@ To have only the summary use the `-s` switch e.g.: `afl-whatsup -s output/` The `paths found` value is a bad indicator how good the coverage is. A better indicator - if you use default llvm instrumentation with at least -version 9 - to use `afl-showmap` on the target with all inputs of the -queue/ directory one after another and collecting the found edge IDs (`-o N.out`), -removing the counters of the edge IDs, making them unique - and there you have -the total number of found instrumented edges. - +version 9 - is to use `afl-showmap` with the collect coverage option `-C` on +the output directory: +``` +$ afl-showmap -C -i out -o /dev/null -- ./target -params @@ +... +[*] Using SHARED MEMORY FUZZING feature. +[*] Target map size: 9960 +[+] Processed 7849 input files. +[+] Captured 4331 tuples (highest value 255, total values 67130596) in '/dev/nul +l'. +[+] A coverage of 4331 edges were achieved out of 9960 existing (43.48%) with 7849 input files. +``` It is even better to check out the exact lines of code that have been reached - and which have not been found so far. @@ -580,6 +588,11 @@ then terminate it. The main node will pick it up and make it available to the other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no free core. +Note that you in nearly all cases you can never reach full coverage. A lot of +functionality is usually behind options that were not activated or fuzz e.g. +if you fuzz a library to convert image formats and your target is the png to +tiff API then you will not touch any of the other library APIs and features. + #### e) How long to fuzz a target? This is a difficult question. diff --git a/TODO.md b/TODO.md index f8ef0e0f..e74fa1d5 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ - AFL_MAP_SIZE for qemu_mode and unicorn_mode - CPU affinity for many cores? There seems to be an issue > 96 cores - - feature for afl-showmap to generate the coverage for all queue entries - afl-plot to support multiple plot_data ## Further down the road diff --git a/docs/Changelog.md b/docs/Changelog.md index 45d640ea..2c57448b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -32,6 +32,8 @@ sending a mail to . - skipping ctors and ifuncs for instrumentation - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR for a fixed map address (eg. 0x10000) + - LTO: laf-intel and redqueen/cmplogare are now applied at link time + to prevent llvm optimizing away the splits - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index efaba122..10cb3fa3 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -246,33 +246,60 @@ static void edit_params(u32 argc, char **argv, char **envp) { // laf if (getenv("LAF_SPLIT_SWITCHES") || getenv("AFL_LLVM_LAF_SPLIT_SWITCHES")) { - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/split-switches-pass.so", obj_path); + if (lto_mode) { + + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); + + } else { + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/split-switches-pass.so", obj_path); + + } } if (getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/compare-transform-pass.so", obj_path); + if (lto_mode) { + + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/compare-transform-pass.so", obj_path); + + } else { + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/compare-transform-pass.so", obj_path); + + } } if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_FLOATS")) { - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/split-compares-pass.so", obj_path); + if (lto_mode) { + + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,-mllvm=-load=%s/split-compares-pass.so", obj_path); + + } else { + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/split-compares-pass.so", obj_path); + + } } @@ -282,24 +309,37 @@ static void edit_params(u32 argc, char **argv, char **envp) { unsetenv("AFL_LD_CALLER"); if (cmplog_mode) { - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/cmplog-routines-pass.so", obj_path); + if (lto_mode) { - // reuse split switches from laf - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/split-switches-pass.so", obj_path); + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,-mllvm=-load=%s/cmplog-routines-pass.so", obj_path); + cc_params[cc_par_cnt++] = + alloc_printf("-Wl,-mllvm=-load=%s/split-switches-pass.so", obj_path); + cc_params[cc_par_cnt++] = alloc_printf( + "-Wl,-mllvm=-load=%s/cmplog-instructions-pass.so", obj_path); - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/cmplog-instructions-pass.so", obj_path); + } else { + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/cmplog-routines-pass.so", obj_path); + + // reuse split switches from laf + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/split-switches-pass.so", obj_path); + + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/cmplog-instructions-pass.so", obj_path); + + } cc_params[cc_par_cnt++] = "-fno-inline"; @@ -314,6 +354,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD); cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; + /* The current LTO instrim mode is not good, so we disable it if (instrument_mode == INSTRUMENT_CFG) @@ -321,6 +362,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { alloc_printf("-Wl,-mllvm=-load=%s/afl-llvm-lto-instrim.so", obj_path); else */ + cc_params[cc_par_cnt++] = alloc_printf( "-Wl,-mllvm=-load=%s/afl-llvm-lto-instrumentation.so", obj_path); cc_params[cc_par_cnt++] = lto_flag; diff --git a/llvm_mode/cmplog-instructions-pass.cc b/llvm_mode/cmplog-instructions-pass.cc index 7c48d906..6ad7dd06 100644 --- a/llvm_mode/cmplog-instructions-pass.cc +++ b/llvm_mode/cmplog-instructions-pass.cc @@ -284,3 +284,7 @@ static RegisterStandardPasses RegisterCmpLogInstructionsPass( static RegisterStandardPasses RegisterCmpLogInstructionsPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogInstructionsPass); +static RegisterStandardPasses RegisterCmpLogInstructionsPassLTO( + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, + registerCmpLogInstructionsPass); + diff --git a/llvm_mode/cmplog-routines-pass.cc b/llvm_mode/cmplog-routines-pass.cc index a0f8f64f..7e5a1ca6 100644 --- a/llvm_mode/cmplog-routines-pass.cc +++ b/llvm_mode/cmplog-routines-pass.cc @@ -204,3 +204,7 @@ static RegisterStandardPasses RegisterCmpLogRoutinesPass( static RegisterStandardPasses RegisterCmpLogRoutinesPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogRoutinesPass); +static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO( + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, + registerCmpLogRoutinesPass); + diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index bed3597a..83885037 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -585,3 +585,6 @@ static RegisterStandardPasses RegisterCompTransPass( static RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerCompTransPass); +static RegisterStandardPasses RegisterCompTransPassLTO( + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerCompTransPass); + diff --git a/llvm_mode/split-compares-pass.so.cc b/llvm_mode/split-compares-pass.so.cc index 3630bd8c..ef3cf7f6 100644 --- a/llvm_mode/split-compares-pass.so.cc +++ b/llvm_mode/split-compares-pass.so.cc @@ -1342,3 +1342,7 @@ static RegisterStandardPasses RegisterSplitComparesPass( static RegisterStandardPasses RegisterSplitComparesTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitComparesPass); +static RegisterStandardPasses RegisterSplitComparesTransPassLTO( + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, + registerSplitComparesPass); + diff --git a/llvm_mode/split-switches-pass.so.cc b/llvm_mode/split-switches-pass.so.cc index f025df77..3a464391 100644 --- a/llvm_mode/split-switches-pass.so.cc +++ b/llvm_mode/split-switches-pass.so.cc @@ -439,3 +439,7 @@ static RegisterStandardPasses RegisterSplitSwitchesTransPass( static RegisterStandardPasses RegisterSplitSwitchesTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerSplitSwitchesTransPass); +static RegisterStandardPasses RegisterSplitSwitchesTransPassLTO( + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, + registerSplitSwitchesTransPass); + diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 0aa116e5..fa9eedc4 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -68,9 +68,11 @@ static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ -static u8 *in_data; /* Input data */ +static u8 *in_data, /* Input data */ + *coverage_map; /* Coverage map */ -static u32 total, highest; /* tuple content information */ +static u64 total; /* tuple content information */ +static u32 tcnt, highest; /* tuple content information */ static u32 in_len, /* Input data length */ arg_offset; /* Total number of execs */ @@ -83,7 +85,8 @@ static u8 quiet_mode, /* Hide non-essential messages? */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1; /* remove shmem? */ + remove_shm = 1, /* remove shmem? */ + collect_coverage; /* collect coverage */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -175,6 +178,25 @@ static void at_exit_handler(void) { } +/* Analyze results. */ + +static void analyze_results(afl_forkserver_t *fsrv) { + + u32 i; + for (i = 0; i < map_size; i++) { + + if (fsrv->trace_bits[i]) { + + total += fsrv->trace_bits[i]; + if (fsrv->trace_bits[i] > highest) highest = fsrv->trace_bits[i]; + if (!coverage_map[i]) { coverage_map[i] = 1; } + + } + + } + +} + /* Write results. */ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { @@ -588,9 +610,14 @@ static void usage(u8 *argv0) { " (Not necessary, here for consistency with other afl-* " "tools)\n\n" "Other settings:\n" - " -i dir - process all files in this directory, -o must be a " + " -i dir - process all files in this directory, must be combined " + "with -o.\n" + " With -C, -o is a file, without -C it must be a " "directory\n" " and each bitmap will be written there individually.\n" + " -C - collect coverage, writes all edges to -o and gives a " + "summary\n" + " Must be combined with -i.\n" " -q - sink program's output and don't show messages\n" " -e - show edge coverage only, ignore hit counts\n" " -r - show real tuple values instead of AFL filter values\n" @@ -624,7 +651,6 @@ int main(int argc, char **argv_orig, char **envp) { s32 opt, i; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; - u32 tcnt = 0; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); @@ -639,10 +665,14 @@ int main(int argc, char **argv_orig, char **envp) { if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } - while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqZQUWbcrh")) > 0) { + while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZQUWbcrh")) > 0) { switch (opt) { + case 'C': + collect_coverage = 1; + break; + case 'i': if (in_dir) { FATAL("Multiple -i options not supported"); } in_dir = optarg; @@ -820,6 +850,13 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !out_file) { usage(argv[0]); } + if (in_dir) { + + if (!out_file && !collect_coverage) + FATAL("for -i you need to specify either -C and/or -o"); + + } + if (fsrv->qemu_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_QEMU; } if (unicorn_mode && !mem_limit_given) { fsrv->mem_limit = MEM_LIMIT_UNICORN; } @@ -910,7 +947,7 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out; + DIR * dir_in, *dir_out = NULL; struct dirent *dir_ent; int done = 0; u8 infile[PATH_MAX], outfile[PATH_MAX]; @@ -924,20 +961,43 @@ int main(int argc, char **argv_orig, char **envp) { 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(in_dir))) { + + closedir(dir_in); + in_dir = dn; + + } else + + ck_free(dn); + if (!be_quiet) ACTF("Reading from directory '%s'...", in_dir); + if (!(dir_in = opendir(in_dir))) { PFATAL("cannot open directory %s", in_dir); } - if (!(dir_out = opendir(out_file))) { + if (!collect_coverage) { + + if (!(dir_out = opendir(out_file))) { + + if (mkdir(out_file, 0700)) { - if (mkdir(out_file, 0700)) { + PFATAL("cannot create output directory %s", out_file); - PFATAL("cannot create output directory %s", out_file); + } } + } else { + + if ((coverage_map = (u8 *)malloc(map_size)) == NULL) + FATAL("coult not grab memory"); + edges_only = 0; + raw_instr_output = 1; + } u8 *use_dir = "."; @@ -978,6 +1038,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); + map_size = fsrv->map_size; if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); @@ -1005,7 +1066,8 @@ int main(int argc, char **argv_orig, char **envp) { if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; #endif - snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); if (read_file(infile)) { @@ -1019,7 +1081,10 @@ int main(int argc, char **argv_orig, char **envp) { showmap_run_target_forkserver(fsrv, in_data, in_len); ck_free(in_data); - tcnt = write_results_to_file(fsrv, outfile); + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); } @@ -1030,6 +1095,13 @@ int main(int argc, char **argv_orig, char **envp) { closedir(dir_in); if (dir_out) { closedir(dir_out); } + if (collect_coverage) { + + memcpy(fsrv->trace_bits, coverage_map, map_size); + tcnt = write_results_to_file(fsrv, out_file); + + } + } else { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) @@ -1043,8 +1115,14 @@ int main(int argc, char **argv_orig, char **envp) { if (!quiet_mode) { if (!tcnt) { FATAL("No instrumentation detected" cRST); } - OKF("Captured %u tuples (highest value %u, total values %u) in '%s'." cRST, + OKF("Captured %u tuples (highest value %u, total values %llu) in " + "'%s'." cRST, tcnt, highest, total, out_file); + if (collect_coverage) + OKF("A coverage of %u edges were achieved out of %u existing (%.02f%%) " + "with %llu input files.", + tcnt, map_size, ((float)tcnt * 100) / (float)map_size, + fsrv->total_execs); } -- cgit 1.4.1 From b5d1a021efaede5e084418fe552330590ee43641 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 13 Aug 2020 22:34:11 +0200 Subject: fix llvm and afl-showmap --- docs/Changelog.md | 1 + llvm_mode/LLVMInsTrim.so.cc | 2 +- llvm_mode/afl-clang-fast.c | 4 ++++ llvm_mode/afl-llvm-common.cc | 4 ++++ llvm_mode/afl-llvm-pass.so.cc | 2 +- src/afl-showmap.c | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 2c57448b..5044dce5 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,6 +29,7 @@ sending a mail to . - added neverzero counting to trace-pc/pcgard - fixes for laf-intel float splitting (thanks to mark-griffin for reporting) + - fixes for llvm 4.0 - skipping ctors and ifuncs for instrumentation - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR for a fixed map address (eg. 0x10000) diff --git a/llvm_mode/LLVMInsTrim.so.cc b/llvm_mode/LLVMInsTrim.so.cc index 2ad7f171..9812b804 100644 --- a/llvm_mode/LLVMInsTrim.so.cc +++ b/llvm_mode/LLVMInsTrim.so.cc @@ -94,7 +94,7 @@ struct InsTrim : public ModulePass { } -#if LLVM_VERSION_MAJOR >= 4 || \ +#if LLVM_VERSION_MAJOR > 4 || \ (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) #define AFL_HAVE_VECTOR_INTRINSICS 1 #endif diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 10cb3fa3..0597ba17 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -371,8 +371,12 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_PCGUARD) { +#if LLVM_VERSION_MAJOR >= 4 cc_params[cc_par_cnt++] = "-fsanitize-coverage=trace-pc-guard"; // edge coverage by default +#else + FATAL("pcguard instrumentation requires llvm 4.0.1+"); +#endif } else { diff --git a/llvm_mode/afl-llvm-common.cc b/llvm_mode/afl-llvm-common.cc index 4b864cf7..4a94ae89 100644 --- a/llvm_mode/afl-llvm-common.cc +++ b/llvm_mode/afl-llvm-common.cc @@ -260,6 +260,8 @@ void scanForDangerousFunctions(llvm::Module *M) { if (!M) return; +#if LLVM_VERSION_MAJOR >= 4 + for (GlobalIFunc &IF : M->ifuncs()) { StringRef ifunc_name = IF.getName(); @@ -325,6 +327,8 @@ void scanForDangerousFunctions(llvm::Module *M) { } +#endif + } static std::string getSourceName(llvm::Function *F) { diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index 2ea9fd84..92823187 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -112,7 +112,7 @@ uint64_t PowerOf2Ceil(unsigned in) { #endif /* #if LLVM_VERSION_STRING >= "4.0.1" */ -#if LLVM_VERSION_MAJOR >= 4 || \ +#if LLVM_VERSION_MAJOR > 4 || \ (LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1) #define AFL_HAVE_VECTOR_INTRINSICS 1 #endif diff --git a/src/afl-showmap.c b/src/afl-showmap.c index fa9eedc4..47c615d8 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -963,7 +963,7 @@ int main(int argc, char **argv_orig, char **envp) { // if a queue subdirectory exists switch to that u8 *dn = alloc_printf("%s/queue", in_dir); - if ((dir_in = opendir(in_dir))) { + if ((dir_in = opendir(dn)) != NULL) { closedir(dir_in); in_dir = dn; -- cgit 1.4.1 From d0ab83a202ef5bb0614dde01825e4dd48f0da645 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Thu, 13 Aug 2020 23:19:05 +0200 Subject: Changelog wording/whitespace --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 5044dce5..3c28ff98 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,7 +33,7 @@ sending a mail to . - skipping ctors and ifuncs for instrumentation - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR for a fixed map address (eg. 0x10000) - - LTO: laf-intel and redqueen/cmplogare are now applied at link time + - LTO: laf-intel and redqueen/cmplog are now applied at link time to prevent llvm optimizing away the splits - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used -- cgit 1.4.1 From e94cc1fae0e78cd6c2e7e3cad737ad039148888f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 14 Aug 2020 07:09:01 +0200 Subject: new faq entries --- docs/FAQ.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/FAQ.md b/docs/FAQ.md index e690635a..997f4c40 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -3,9 +3,11 @@ ## Contents 1. [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) - 2. [What is an edge?](#what-is-an-edge) - 3. [Why is my stability below 100%?](#why-is-my-stability-below-100) - 4. [How can I improve the stability value](#how-can-i-improve-the-stability-value) + 2. [How do I fuzz a network service?](#how-to-fuzz-a-network-service) + 3. [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program) + 4. [What is an edge?](#what-is-an-edge) + 5. [Why is my stability below 100%?](#why-is-my-stability-below-100) + 6. [How can I improve the stability value](#how-can-i-improve-the-stability-value) If you find an interesting or important question missing, submit it via [https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues) @@ -20,6 +22,43 @@ If you find an interesting or important question missing, submit it via 6. Running on an `ext2` filesystem with `noatime` mount option will be a bit faster than on any other journaling filesystem 7. Use your cores! [README.md:3.b) Using multiple cores/threads](../README.md#b-using-multiple-coresthreads) +## How do I fuzz a network service? + +The short answer is - you cannot, at least "out of the box". + +Using network has a slow-down of x10-20 on the fuzzing speed, does not scale, +and finally usually it is more than one initial data packet but a back-and-forth +which is totally unsupported by most coverage aware fuzzers. + +The established method to fuzz network services is to modify the source code +to read from a file or stdin (fd 0) (or even faster via shared memory, combine +this with persistent mode [llvm_mode/README.persistent_mode.md](llvm_mode/README.persistent_mode.md) +and you have a performance gain of x10 instead of a performance loss of over +x10 - that is a x100 difference! + +If modifying the source is not an option (e.g. because you only have a binary +and perform binary fuzzing) you can also use a shared library with AFL_PRELOAD +to emulate the network. This is also much faster than network would be. +See [examples/socket_fuzzing/](../examples/socket_fuzzing/) + +There is an outdated afl++ branch that implements networking if you are +desperate though: [https://github.com/AFLplusplus/AFLplusplus/tree/networking](https://github.com/AFLplusplus/AFLplusplus/tree/networking) - +however a better option is AFLnet ([https://github.com/aflnet/aflnet](https://github.com/aflnet/aflnet)) +which allows you to define network state with different type of data packets. + +## How do I fuzz a GUI program? + +If the GUI program can read the fuzz data from a file (via the command line, +a fixed location or via an environment variable) without needing any user +interaction then then yes. + +Otherwise it is not possible without modifying the source code - which is a +very good idea anyway as the GUI functionality is a huge CPU/time overhead +for the fuzzing. + +So create a new `main()` that just reads the test case and calls the +functionality for processing the input that the GUI program is using. + ## What is an "edge" A program contains `functions`, `functions` contain the compiled machine code. -- cgit 1.4.1 From 1cf473848789b340134b68b02d793c6d90f746a8 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 15 Aug 2020 10:27:40 +0200 Subject: more FAQ --- docs/FAQ.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 13 deletions(-) (limited to 'docs') diff --git a/docs/FAQ.md b/docs/FAQ.md index 997f4c40..93a87a72 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -2,16 +2,39 @@ ## Contents - 1. [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) - 2. [How do I fuzz a network service?](#how-to-fuzz-a-network-service) - 3. [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program) - 4. [What is an edge?](#what-is-an-edge) - 5. [Why is my stability below 100%?](#why-is-my-stability-below-100) - 6. [How can I improve the stability value](#how-can-i-improve-the-stability-value) + * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) + * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) + * [How do I fuzz a network service?](#how-to-fuzz-a-network-service) + * [How do I fuzz a GUI program?](#how-to-fuzz-a-gui-program) + * [What is an edge?](#what-is-an-edge) + * [Why is my stability below 100%?](#why-is-my-stability-below-100) + * [How can I improve the stability value](#how-can-i-improve-the-stability-value) If you find an interesting or important question missing, submit it via [https://github.com/AFLplusplus/AFLplusplus/issues](https://github.com/AFLplusplus/AFLplusplus/issues) +## What is the difference between afl and afl++? + +American Fuzzy Lop (AFL) was developed by MichaƂ "lcamtuf" Zalewski starting in +2013/2014, and when he left Google end of 2017 he stopped developing it. + +At the end of 2019 the Google fuzzing team took over maintance of AFL, however +it is only accepting PR from the community and is not developing enhancements +anymore. + +In the second quarter of 2019, 1 1/2 years after no further development of +AFL had happened and it became clear there would be none coming, afl++ +was born, where initially first community patches were collected and applied +for bugs and enhancements. Then from various AFL spin-offs - mostly academic +research - features were integrated. This already resulted in a much advanced +AFL. + +Until the end of 2019 the afl++ team had grown to four active developers which +then implemented their own research and feature, making it now by far the most +flexible and feature rich guided fuzzer available as open source. +And in independent fuzzing benchmarks it is one of the best fuzzers available, +e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) + ## How to improve the fuzzing speed 1. use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) @@ -101,15 +124,15 @@ code example above): ``` Every line between two blocks is an `edge`. -## Why is my stability below 100 +## Why is my stability below 100% Stability is measured by how many percent of the edges in the target are "stable". Sending the same input again and again should take the exact same path through the target every time. If that is the case, the stability is 100%. -If however randomness happens, e.g. a thread reading from shared memory, +If however randomness happens, e.g. a thread reading other external data, reaction to timing, etc. then in some of the re-executions with the same data -will result in the edge information being different accross runs. +the result in the edge information will be different accross runs. Those edges that change are then flagged "unstable". The more "unstable" edges, the more difficult for afl++ to identify valid new @@ -122,9 +145,25 @@ improve the stability. ## How can I improve the stability value +For fuzzing a 100% stable target that covers all edges is the best. +A 90% stable target that covers all edges is however better than a 100% stable +target that ignores 10% of the edges. + +With instability you basically have a partial coverage loss on an edge, with +ignore you have a full loss on that edge. + +There are functions that are unstable, but also provide value to coverage, eg +init functions that use fuzz data as input for example. +If however it is a function that has nothing to do with the input data is the +source, e.g. checking jitter, or is a hash map function etc. then it should +not be instrumented. + +To be able to make this decision the following process will allow you to +identify the functions with variable edges so you can make this decision. + Four steps are required to do this and requires quite some knowledge of coding and/or disassembly and it is only effectively possible with -afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! +afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation. 1. First step: Identify which edge ID numbers are unstable @@ -135,9 +174,9 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! 2. Second step: Find the responsible function. a) For LTO instrumented binaries this can be documented during compile - time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/afile`. - This file will have one assigned edge ID and the corresponding function - per line. + time, just set `export AFL_LLVM_DOCUMENT_IDS=/path/to/a/file`. + This file will have one assigned edge ID and the corresponding + function per line. b) For PCGUARD instrumented binaries it is much more difficult. Here you can either modify the __sanitizer_cov_trace_pc_guard function in @@ -151,6 +190,10 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! on start, check to which memory address the edge ID value is written and set a write breakpoint to that address (`watch 0x.....`). + c) in all other instrumentation types this is not possible. So just + recompile with the the two mentioned above. This is just for + identifying the functions that have unstable edges. + 3. Third step: create a text file with the filenames/functions Identify which source code files contain the functions that you need to @@ -161,6 +204,15 @@ afl-clang-fast PCGUARD and afl-clang-lto LTO instrumentation! If PCGUARD is used, then you need to follow this guide (needs llvm 12+!): [http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation](http://clang.llvm.org/docs/SanitizerCoverage.html#partially-disabling-instrumentation) + Only deny those functions from instrumentation that provide no value + for coverage - that is if it does not process any fuzz data directly + or indirectly (e.g. hash maps, thread management etc.). + If however a function directly or indirectly handles fuzz data then you + should not put the function in a deny instrumentation list and rather + live with the instability it comes with. + 4. Fourth step: recompile the target Recompile, fuzz it, be happy :) + + This link explains this process for [Fuzzbench](https://github.com/google/fuzzbench/issues/677) -- cgit 1.4.1 From 0a251f93e0842c92755e9bcba61e520669a6c2e6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 15 Aug 2020 13:34:51 +0200 Subject: increase initial memory sized --- docs/Changelog.md | 2 ++ examples/aflpp_driver/aflpp_driver.c | 1 - include/config.h | 10 +++++----- llvm_mode/afl-llvm-rt.o.c | 12 ++++-------- 4 files changed, 11 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3c28ff98..ea7c7caf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,6 +12,8 @@ sending a mail to . ### Version ++2.66d (devel) - Support for improved afl++ snapshot module: https://github.com/AFLplusplus/AFL-Snapshot-LKM + - Due to the instrumentation needing more memory, the initial memory sizes + for -m have been increased - afl-fuzz: - added -F option to allow -M main fuzzers to sync to foreign fuzzers, e.g. honggfuzz or libfuzzer diff --git a/examples/aflpp_driver/aflpp_driver.c b/examples/aflpp_driver/aflpp_driver.c index b764338e..ff5446e9 100644 --- a/examples/aflpp_driver/aflpp_driver.c +++ b/examples/aflpp_driver/aflpp_driver.c @@ -109,7 +109,6 @@ If 1, close stdout at startup. If 2 close stderr; if 3 close both. int __afl_sharedmem_fuzzing = 1; extern unsigned int * __afl_fuzz_len; extern unsigned char *__afl_fuzz_ptr; -// extern struct cmp_map *__afl_cmp_map; // libFuzzer interface is thin, so we don't include any libFuzzer headers. int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); diff --git a/include/config.h b/include/config.h index 344a368f..a978a27c 100644 --- a/include/config.h +++ b/include/config.h @@ -70,21 +70,21 @@ #ifndef __NetBSD__ #ifndef WORD_SIZE_64 - #define MEM_LIMIT 25 - #else #define MEM_LIMIT 50 + #else + #define MEM_LIMIT 75 #endif /* ^!WORD_SIZE_64 */ #else /* NetBSD's kernel needs more space for stack, see discussion for issue \ #165 */ - #define MEM_LIMIT 200 + #define MEM_LIMIT 250 #endif /* Default memory limit when running in QEMU mode (MB): */ -#define MEM_LIMIT_QEMU 200 +#define MEM_LIMIT_QEMU 250 /* Default memory limit when running in Unicorn mode (MB): */ -#define MEM_LIMIT_UNICORN 200 +#define MEM_LIMIT_UNICORN 250 /* Number of calibration cycles per every new test case (and for test cases that show variable behavior): */ diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 5479c3da..a56b54b2 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -902,15 +902,11 @@ __attribute__((constructor(0))) void __afl_auto_first(void) { if (getenv("AFL_DISABLE_LLVM_INSTRUMENTATION")) return; u8 *ptr; + u32 get_size = __afl_final_loc ? __afl_final_loc : 1024000; - if (__afl_final_loc > MAP_INITIAL_SIZE) { - - ptr = (u8 *)mmap(NULL, __afl_final_loc, PROT_READ | PROT_WRITE, MAP_PRIVATE, - -1, 0); - - if (ptr && (ssize_t)ptr != -1) { __afl_area_ptr = ptr; } - - } + ptr = (u8 *)mmap(NULL, __afl_final_loc, PROT_READ | PROT_WRITE, MAP_PRIVATE, + -1, 0); + if (ptr && (ssize_t)ptr != -1) { __afl_area_ptr = ptr; } } -- cgit 1.4.1 From cc1fe2f2d29b4b306c1558189251adae781dbb70 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 15 Aug 2020 22:59:49 +0200 Subject: skip instrumenting blocks following __afl_loop to improve stability in LTO. not in afl-llvm-pass and instrim because they are outdated, sancov cant be fixed --- docs/Changelog.md | 2 ++ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 41 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index ea7c7caf..ead4ff26 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,8 @@ sending a mail to . - skipping ctors and ifuncs for instrumentation - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR for a fixed map address (eg. 0x10000) + - LTO: improved stability for persistent mode, no other instrumentation + has that advantage - LTO: laf-intel and redqueen/cmplog are now applied at link time to prevent llvm optimizing away the splits - LTO: autodictionary mode is a default diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index a4caf77b..2b99d4c6 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -103,6 +103,7 @@ bool AFLLTOPass::runOnModule(Module &M) { std::vector dictionary; std::vector calls; DenseMap valueMap; + std::vector BlockList; char * ptr; FILE * documentFile = NULL; @@ -310,6 +311,24 @@ bool AFLLTOPass::runOnModule(Module &M) { isStrncasecmp &= !FuncName.compare("strncasecmp"); isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64"); + /* we do something different here, putting this BB and the + successors in a block map */ + if (!FuncName.compare("__afl_persistent_loop")) { + + BlockList.push_back(&BB); + /* + for (succ_iterator SI = succ_begin(&BB), SE = + succ_end(&BB); SI != SE; ++SI) { + + BasicBlock *succ = *SI; + BlockList.push_back(succ); + + } + + */ + + } + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && !isStrncasecmp && !isIntMemcpy) continue; @@ -603,6 +622,28 @@ bool AFLLTOPass::runOnModule(Module &M) { uint32_t fs = origBB->getParent()->size(); uint32_t countto; + if (BlockList.size()) { + + int skip = 0; + for (uint32_t k = 0; k < BlockList.size(); k++) { + + if (origBB == BlockList[k]) { + + if (debug) + fprintf( + stderr, + "DEBUG: Function %s skipping BB with/after __afl_loop\n", + F.getName().str().c_str()); + skip = 1; + + } + + } + + if (skip) continue; + + } + for (succ_iterator SI = succ_begin(origBB), SE = succ_end(origBB); SI != SE; ++SI) { -- cgit 1.4.1 From 1d56de6c1d24e6ed24bf7193df18110da753c6b2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 16 Aug 2020 13:29:24 +0200 Subject: fix lto autodict for long strings --- docs/Changelog.md | 1 + llvm_mode/afl-llvm-lto-instrumentation.so.cc | 33 ++++++++++++++++++---------- llvm_mode/afl-llvm-rt.o.c | 5 +++-- 3 files changed, 25 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index ead4ff26..55b0c7dd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -37,6 +37,7 @@ sending a mail to . for a fixed map address (eg. 0x10000) - LTO: improved stability for persistent mode, no other instrumentation has that advantage + - LTO: fixed autodict for long strings - LTO: laf-intel and redqueen/cmplog are now applied at link time to prevent llvm optimizing away the splits - LTO: autodictionary mode is a default diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 2b99d4c6..5320df09 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -291,14 +291,14 @@ bool AFLLTOPass::runOnModule(Module &M) { if ((callInst = dyn_cast(&IN))) { - bool isStrcmp = true; - bool isMemcmp = true; - bool isStrncmp = true; - bool isStrcasecmp = true; - bool isStrncasecmp = true; - bool isIntMemcpy = true; - bool addedNull = false; - uint8_t optLen = 0; + bool isStrcmp = true; + bool isMemcmp = true; + bool isStrncmp = true; + bool isStrcasecmp = true; + bool isStrncasecmp = true; + bool isIntMemcpy = true; + bool addedNull = false; + size_t optLen = 0; Function *Callee = callInst->getCalledFunction(); if (!Callee) continue; @@ -546,17 +546,26 @@ bool AFLLTOPass::runOnModule(Module &M) { // add null byte if this is a string compare function and a null // was not already added - if (addedNull == false && !isMemcmp) { + if (!isMemcmp) { - thestring.append("\0", 1); // add null byte - optLen++; + if (addedNull == false) { + + thestring.append("\0", 1); // add null byte + optLen++; + + } + + // ensure we do not have garbage + size_t offset = thestring.find('\0', 0); + if (offset + 1 < optLen) optLen = offset + 1; + thestring = thestring.substr(0, optLen); } if (!be_quiet) { std::string outstring; - fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen, + fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen, (unsigned int)thestring.length()); for (uint8_t i = 0; i < thestring.length(); i++) { diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index e5ff7b19..d00fd26f 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -329,8 +329,9 @@ static void __afl_map_shm(void) { __afl_area_ptr[0] = 1; - } else if (__afl_map_addr && - (!__afl_area_ptr || __afl_area_ptr == __afl_area_initial)) { + } else if ((!__afl_area_ptr || __afl_area_ptr == __afl_area_initial) && + + __afl_map_addr) { __afl_area_ptr = mmap((void *)__afl_map_addr, __afl_map_size, PROT_READ | PROT_WRITE, -- cgit 1.4.1