From 0c2e998f69b060867461cd903989dfe99252a8e3 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 9 Apr 2020 10:30:24 +0200 Subject: 2.63d init --- docs/Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 70753fcc..dd135b7e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,10 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++2.63d (development): + - ... + + ### Version ++2.63c (release): ! the repository was moved from vanhauser-thc to AFLplusplus. It is now -- cgit 1.4.1 From c1395bb543b3b02b491d1c16374af6efbc77a5d2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 9 Apr 2020 10:36:28 +0200 Subject: LTO llvm11 (#302) * new LTO mode for llvm 11 * remove unneeded afl-ld and env vars --- docs/Changelog.md | 2 +- llvm_mode/GNUmakefile | 34 +- llvm_mode/README.lto.md | 163 +----- llvm_mode/afl-clang-fast.c | 21 +- llvm_mode/afl-ld.c | 839 --------------------------- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 5 +- 6 files changed, 60 insertions(+), 1004 deletions(-) delete mode 100644 llvm_mode/afl-ld.c (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index dd135b7e..18f38551 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -45,7 +45,7 @@ sending a mail to . easier: DEFAULT, CFG (INSTRIM), LTO, CTX, NGRAM-x (x=2-16) - made USE_TRACE_PC compile obsolete - LTO collision free instrumented added in llvm_mode with afl-clang-lto - - note that this mode is amazing, but quite some targets won't compile + this mode is amazing but requires you to build llvm 11 yourself - Added llvm_mode NGRAM prev_loc coverage by Adrean Herrera (https://github.com/adrianherrera/afl-ngram-pass/), activate by setting AFL_LLVM_INSTRUMENT=NGRAM- or AFL_LLVM_NGRAM_SIZE= diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index e3708efa..ce60dd1c 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -58,19 +58,20 @@ endif ifeq "$(LLVM_MAJOR)" "9" $(info [+] llvm_mode detected llvm 9, enabling neverZero implementation) - $(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation) - LLVM_LTO = 1 endif ifeq "$(LLVM_NEW_API)" "1" $(info [+] llvm_mode detected llvm 10+, enabling neverZero implementation and c++14) - $(info [+] llvm_mode detected llvm 9, enabling afl-clang-lto LTO implementation) LLVM_STDCXX = c++14 +endif + +ifeq "$(LLVM_MAJOR)" "11" + $(info [+] llvm_mode detected llvm 11, enabling afl-clang-lto LTO implementation) LLVM_LTO = 1 endif ifeq "$(LLVM_LTO)" "0" - $(info [+] llvm_mode detected llvm < 9, afl-clang-lto LTO will not be build.) + $(info [+] llvm_mode detected llvm < 11, afl-clang-lto LTO will not be build.) endif ifeq "$(LLVM_APPLE)" "1" @@ -125,14 +126,18 @@ else endif endif -ifneq "$(AFL_CLANG_FLTO)" "" -ifeq "$(AFL_REAL_LD)" "" - AFL_REAL_LD = $(shell readlink /bin/ld 2>/dev/null) - ifeq "$(AFL_REAL_LD)" "" - AFL_REAL_LD = $(shell readlink /usr/bin/ld 2>/dev/null) +ifeq "$(LLVM_LTO)" "1" + ifneq "$(AFL_CLANG_FLTO)" "" + ifeq "$(AFL_REAL_LD)" "" + ifneq "$(shell readlink $(LLVM_BINDIR)/ld.lld 2>&1)" "" + AFL_REAL_LD = $(LLVM_BINDIR)/ld.lld + else + $(warn ld.lld not found, can not enable LTO mode) + LLVM_LTO = 0 + endif + endif endif endif -endif AFL_CLANG_FUSELD= ifneq "$(AFL_CLANG_FLTO)" "" @@ -257,10 +262,11 @@ ifeq "$(LLVM_LTO)" "1" $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) ln -sf afl-ld ../ld @rm -f .test-instr - @-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -Wl,--afl -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto and afl-ld seem to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto" + @-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto seems to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto" @rm -f .test-instr endif endif + ../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps -$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) @@ -275,9 +281,9 @@ ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CFL) -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) endif -../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc MarkNodes.cc +../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc ifeq "$(LLVM_LTO)" "1" - $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) + $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) endif # laf @@ -323,7 +329,7 @@ all_done: test_build install: all install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../afl-clang-lto -a -f ../afl-ld ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-ld $${DESTDIR}$(HELPER_PATH); ln -sf afl-ld $${DESTDIR}$(HELPER_PATH)/ld; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi + if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 28b3b045..a3c7ddc3 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -2,16 +2,15 @@ ## TLDR; -1. This compile mode is very frickle if it works it is amazing, if it fails - - well use afl-clang-fast +This version requires a current llvm 11 compiled from the github master. -2. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better +1. Use afl-clang-lto/afl-clang-lto++ because it is faster and gives better coverage than anything else that is out there in the AFL world -3. You can use it together with llvm_mode: laf-intel and whitelisting +2. You can use it together with llvm_mode: laf-intel and whitelisting features and can be combined with cmplog/Redqueen -4. It only works with llvm 9 (and likely 10+ but is not tested there yet) +3. It only works with llvm 11 (current github master state) ## Introduction and problem description @@ -63,6 +62,26 @@ afl-llvm-lto++2.62d by Marc "vanHauser" Heuse [+] Linker was successful ``` +## Building llvm 11 + +``` +$ sudo apt install binutils-dev +$ git clone https://github.com/llvm/llvm-project +$ cd llvm-project +$ mkdir build +$ cd build +$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ +$ make +$ export PATH=`pwd`/bin:$PATH +$ export LLVM_CONFIG=`pwd`/bin/llcm-config +$ cd /path/to/AFLplusplus/ +$ make +$ cd llvm_mode +$ make +$ cd .. +$ make install +``` + ## How to use afl-clang-lto Just use afl-clang-lto like you did afl-clang-fast or afl-gcc. @@ -94,129 +113,12 @@ AR=llvm-ar RANLIB=llvm-ranlib CC=afl-clang-lto CXX=afl-clang-lto++ ./configure - ``` and on some target you have to to AR=/RANLIB= even for make as the configure script does not save it ... -### "linking globals named '...': symbol multiply defined" error - -The target program is using multiple global variables or functions with the -same name. This is a common error when compiling a project with LTO, and -the fix is `-Wl,--allow-multiple-definition` - however llvm-link which we -need to link all llvm IR LTO files does not support this - yet (hopefully). -Hence if you see this error either you have to remove the duplicate global -variable (think `#ifdef` ...) or you are out of luck. :-( - -### "expected top-level entity" + binary ouput error - -This happens if multiple .a archives are to be linked and they contain the -same object filenames, the first in LTO form, the other in ELF form. -This can not be fixed programmatically, but can be fixed by hand. -You can try to delete the file from either archive -(`llvm-ar d .a .o`) or performing the llvm-linking, optimizing -and instrumentation by hand (see below). - -### "undefined reference to ..." - -This *can* be the opposite situation of the "expected top-level entity" error - -the library with the ELF file is before the LTO library. -However it can also be a bug in the program - try to compile it normally. If -fails then it is a bug in the program. -Solutions: You can try to delete the file from either archive, e.g. -(`llvm-ar d .a .o`) or performing the llvm-linking, optimizing -and instrumentation by hand (see below). - -### "File format not recognized" - -This happens if the build system has fixed LDFLAGS, CPPFLAGS, CXXFLAGS and/or -CFLAGS. Ensure that they all contain the `-flto` flag that afl-clang-lto was -compiled with (you can see that by typing `afl-clang-lto -h` and inspecting -the last line of the help output) and add them otherwise - -### clang is hardcoded to /bin/ld - -Some clang packages have 'ld' hardcoded to /bin/ld. This is an issue as this -prevents "our" afl-ld being called. - --fuse-ld=/path/to/afl-ld should be set through makefile magic in llvm_mode - -if it is supported - however if this fails you can try: -``` -LDFLAGS=-fuse-ld=&1 | grep afl-clang-lto | tail -n 1` - -2. run this command prepended with AFL_DEBUG=1 and collect the afl-ld command - parameters, e.g. `AFL_DEBUG=1 afl-clang-lto[++] .... | grep /afl/ld` - -3. for every .a archive you want to instrument unpack it into a seperate - directory, e.g. - `mkdir archive1.dir ; cd archive1.dir ; llvm-link x ../.a` - -4. run `file archive*.dir/*.o` and make two lists, one containing all ELF files - and one containing all LLVM IR bitcode files. - You do the same for all .o files of the ../afl/ld command options - -5. Create a single bitcode file by using llvm-link, e.g. - `llvm-link -o all-bitcode.bc ` - If this fails it is game over - or you modify the source code - -6. Run the optimizer on the new bitcode file: - `opt -O3 --polly -o all-optimized.bc all-bitcode.bc` - -7. Instrument the optimized bitcode file: - `opt --load=$AFL_PATH/afl-llvm-lto-instrumentation.so --disable-opt --afl-lto all-optimized.bc -o all-instrumented.bc - -8. If the parameter `--allow-multiple-definition` is not in the list, add it - as first command line option. - -9. Link everything together. - a) You use the afl-ld command and instead of e.g. `/usr/local/lib/afl/ld` - you replace that with `ld`, the real linker. - b) Every .a archive you instrumented files from you remove the .a - or -l from the command - c) If you have entries in your ELF files list (see step 4), you put them to - the command line - but them in the same order! - d) put the all-instrumented.bc before the first library or .o file - e) run the command and hope it compiles, if it doesn't you have to analyze - what the issue is and fix that in the approriate step above. - -Yes this is long and complicated. That is why there is afl-ld doing this and -that why this can easily fail and not all different ways how it *can* fail can -be implemented ... - ### compiling programs still fail afl-clang-lto is still work in progress. -Complex targets are still likely not to compile and this needs to be fixed. Please report issues at: [https://github.com/AFLplusplus/AFLplusplus/issues/226](https://github.com/AFLplusplus/AFLplusplus/issues/226) -Known issues: -* ffmpeg -* bogofilter -* libjpeg-turbo-1.3.1 - ## Upcoming Work 1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions @@ -225,15 +127,6 @@ Known issues: Result: faster fork in the target and faster map analysis in afl-fuzz => more speed :-) -## Tested and working targets - -* libpng-1.2.53 -* libxml2-2.9.2 -* tiff-4.0.4 -* unrar-nonfree-5.6.6 -* exiv 0.27 -* jpeg-6b - ## History This was originally envisioned by hexcoder- in Summer 2019, however we saw no @@ -252,11 +145,17 @@ very difficult with a program that has so many paths and therefore so many dependencies. At lot of stratgies were implemented - and failed. And then sat solvers were tried, but with over 10.000 variables that turned out to be a dead-end too. + The final idea to solve this came from domenukk who proposed to insert a block into an edge and then just use incremental counters ... and this worked! After some trials and errors to implement this vanhauser-thc found out that there is actually an llvm function for this: SplitEdge() :-) + Still more problems came up though as this only works without bugs from llvm 9 onwards, and with high optimization the link optimization ruins the instrumented control flow graph. -As long as there are no larger changes in llvm this all should work well now ... + +This is all now fixed with llvm 11. The llvm's own linker is now able to +load passes and this bypasses all problems we had. + +Happy end :) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index e2b44def..9d8ebdec 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -269,12 +269,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (instrument_mode == INSTRUMENT_LTO) { - char *old_path = getenv("PATH"); - char *new_path = alloc_printf("%s:%s", AFL_PATH, old_path); - - setenv("PATH", new_path, 1); - setenv("AFL_LD", "1", 1); - if (getenv("AFL_LLVM_WHITELIST") != NULL) { cc_params[cc_par_cnt++] = "-Xclang"; @@ -285,13 +279,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } -#ifdef AFL_CLANG_FUSELD - cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s/afl-ld", AFL_PATH); -#endif - - cc_params[cc_par_cnt++] = "-B"; - cc_params[cc_par_cnt++] = AFL_PATH; - + cc_params[cc_par_cnt++] = alloc_printf("-fuse-ld=%s", AFL_REAL_LD); + cc_params[cc_par_cnt++] = "-Wl,--allow-multiple-definition"; + 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; } else { @@ -738,9 +729,7 @@ int main(int argc, char **argv, char **envp) { "bb\n" "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " "global var\n" - "AFL_REAL_LD: use this linker instead of the compiled in path\n" - "AFL_LD_PASSTHROUGH: do not perform instrumentation (for configure " - "scripts)\n" + "AFL_REAL_LD: use this lld linker instead of the compiled in path\n" "\nafl-clang-lto was built with linker target \"%s\" and LTO flags " "\"%s\"\n" "If anything fails - be sure to read README.lto.md!\n", diff --git a/llvm_mode/afl-ld.c b/llvm_mode/afl-ld.c deleted file mode 100644 index eb46c85c..00000000 --- a/llvm_mode/afl-ld.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - american fuzzy lop++ - wrapper for GNU ld - ----------------------------------------- - - Written by Marc Heuse for afl++ - - Maintained by Marc Heuse , - Heiko Eißfeldt - Andrea Fioraldi - Dominik Maier - - Copyright 2019-2020 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: - - http://www.apache.org/licenses/LICENSE-2.0 - - The sole purpose of this wrapper is to preprocess clang LTO files before - linking by ld and perform the instrumentation on the whole program. - -*/ - -#define AFL_MAIN - -#include "config.h" -#include "types.h" -#include "debug.h" -#include "alloc-inl.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#define MAX_PARAM_COUNT 4096 - -static u8 **ld_params, /* Parameters passed to the real 'ld' */ - **link_params, /* Parameters passed to 'llvm-link' */ - **opt_params, /* Parameters passed to 'opt' opt */ - **inst_params; /* Parameters passed to 'opt' inst */ - -static u8 *input_file; /* Originally specified input file */ -static u8 *final_file, /* Instrumented file for the real 'ld' */ - *linked_file, /* file where we link all files */ - *modified_file; /* file that was optimized before instr */ -static u8 *afl_path = AFL_PATH; -static u8 *real_ld = AFL_REAL_LD; -static u8 cwd[4096]; -static u8 *tmp_dir; -static u8 *ar_dir; -static u8 ar_dir_cnt; -static u8 *libdirs[254]; -static u8 libdir_cnt; - -static u8 be_quiet, /* Quiet mode (no stderr output) */ - debug, /* AFL_DEBUG */ - passthrough, /* AFL_LD_PASSTHROUGH - no link+optimize*/ - we_link, /* we have bc/ll -> link + optimize */ - just_version; /* Just show version? */ - -static u32 ld_param_cnt = 1, /* Number of params to 'ld' */ - link_param_cnt = 1, /* Number of params to 'llvm-link' */ - opt_param_cnt = 1, /* Number of params to 'opt' opt */ - inst_param_cnt = 1; /* Number of params to 'opt' instr */ - -/* This function wipes a directory - our AR unpack directory in this case */ -static u8 wipe_directory(u8 *path) { - - DIR * d; - struct dirent *d_ent; - - d = opendir(path); - - if (!d) return 0; - - while ((d_ent = readdir(d))) { - - if (strcmp(d_ent->d_name, ".") != 0 && strcmp(d_ent->d_name, "..") != 0) { - - u8 *fname = alloc_printf("%s/%s", path, d_ent->d_name); - if (unlink(fname)) PFATAL("Unable to delete '%s'", fname); - ck_free(fname); - - } - - } - - closedir(d); - - return !!rmdir(path); - -} - -/* remove temporary files on fatal errors */ -static void at_exit_handler(void) { - - if (!getenv("AFL_KEEP_ASSEMBLY")) { - - if (linked_file) { - - unlink(linked_file); - linked_file = NULL; - - } - - if (modified_file) { - - unlink(modified_file); - modified_file = NULL; - - } - - if (final_file) { - - unlink(final_file); - final_file = NULL; - - } - - if (ar_dir != NULL) { - - wipe_directory(ar_dir); - ar_dir = NULL; - - } - - } - -} - -/* This function checks if the parameter is a) an existing file and b) - if it is a BC or LL file, if both are true it returns 1 and 0 otherwise */ -int is_llvm_file(const char *file) { - - int fd; - u8 buf[5]; - - if ((fd = open(file, O_RDONLY)) < 0) { - - if (debug) SAYF(cMGN "[D] " cRST "File %s not found", file); - return 0; - - } - - if (read(fd, buf, 4) != 4) return 0; - buf[sizeof(buf) - 1] = 0; - - close(fd); - - if (strncmp(buf, "; Mo", 4) == 0) return 1; - - if (buf[0] == 'B' && buf[1] == 'C' && buf[2] == 0xc0 && buf[3] == 0xde) - return 1; - - return 0; - -} - -/* Return the current working directory, not thread safe ;-) */ -u8 *getthecwd() { - - static u8 fail[] = ""; - if (getcwd(cwd, sizeof(cwd)) == NULL) return fail; - return cwd; - -} - -/* Check if an ar extracted file is already in the parameter list */ -int is_duplicate(u8 **params, u32 ld_param_cnt, u8 *ar_file) { - - for (uint32_t i = 0; i < ld_param_cnt; i++) - if (params[i] != NULL) - if (strcmp(params[i], ar_file) == 0) return 1; - - return 0; - -} - -/* Examine and modify parameters to pass to 'ld', 'llvm-link' and 'llmv-ar'. - Note that the file name is always the last parameter passed by GCC, - so we exploit this property to keep the code "simple". */ -static void edit_params(int argc, char **argv) { - - u32 i, have_lto = 0, libdir_index; - u8 libdir_file[4096]; - - if (tmp_dir == NULL) { - - tmp_dir = getenv("TMPDIR"); - if (!tmp_dir) tmp_dir = getenv("TEMP"); - if (!tmp_dir) tmp_dir = getenv("TMP"); - if (!tmp_dir) tmp_dir = "/tmp"; - - } - - linked_file = - alloc_printf("%s/.afl-%u-%u-1.ll", tmp_dir, getpid(), (u32)time(NULL)); - modified_file = - alloc_printf("%s/.afl-%u-%u-2.bc", tmp_dir, getpid(), (u32)time(NULL)); - final_file = - alloc_printf("%s/.afl-%u-%u-3.bc", tmp_dir, getpid(), (u32)time(NULL)); - - ld_params = ck_alloc(4096 * sizeof(u8 *)); - link_params = ck_alloc(4096 * sizeof(u8 *)); - inst_params = ck_alloc(12 * sizeof(u8 *)); - opt_params = ck_alloc(12 * sizeof(u8 *)); - - ld_params[0] = (u8 *)real_ld; - ld_params[ld_param_cnt++] = "--allow-multiple-definition"; - - link_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-link"); - link_params[link_param_cnt++] = "-S"; // we create the linked file as .ll - link_params[link_param_cnt++] = "-o"; - link_params[link_param_cnt++] = linked_file; - - opt_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt"); - if (getenv("AFL_DONT_OPTIMIZE") == NULL) - opt_params[opt_param_cnt++] = "-O3"; - else - opt_params[opt_param_cnt++] = "-O0"; - - // opt_params[opt_param_cnt++] = "-S"; // only when debugging - opt_params[opt_param_cnt++] = linked_file; // input: .ll file - opt_params[opt_param_cnt++] = "-o"; - opt_params[opt_param_cnt++] = modified_file; // output: .bc file - - inst_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "opt"); - inst_params[inst_param_cnt++] = - alloc_printf("--load=%s/afl-llvm-lto-instrumentation.so", afl_path); - // inst_params[inst_param_cnt++] = "-S"; // only when debugging - inst_params[inst_param_cnt++] = "--disable-opt"; - inst_params[inst_param_cnt++] = "--afl-lto"; - inst_params[inst_param_cnt++] = modified_file; // input: .bc file - inst_params[inst_param_cnt++] = "-o"; - inst_params[inst_param_cnt++] = final_file; // output: .bc file - - // first we must collect all library search paths - for (i = 1; i < argc; i++) - if (strlen(argv[i]) > 2 && argv[i][0] == '-' && argv[i][1] == 'L') - libdirs[libdir_cnt++] = argv[i] + 2; - - // then we inspect all options to the target linker - for (i = 1; i < argc; i++) { - - if (ld_param_cnt >= MAX_PARAM_COUNT || link_param_cnt >= MAX_PARAM_COUNT) - FATAL( - "Too many command line parameters because of unpacking .a archives, " - "this would need to be done by hand ... sorry! :-("); - - if (strncmp(argv[i], "-flto", 5) == 0) have_lto = 1; - - if (!strcmp(argv[i], "-version")) { - - just_version = 1; - ld_params[1] = argv[i]; - ld_params[2] = NULL; - final_file = input_file; - return; - - } - - if (strcmp(argv[i], "--afl") == 0) { - - if (!be_quiet) OKF("afl++ test command line flag detected, exiting."); - exit(0); - - } - - // if a -l library is linked and no .so is found but an .a archive is there - // then the archive will be used. So we have to emulate this and check - // if an archive will be used and if yes we will instrument it too - libdir_file[0] = 0; - libdir_index = libdir_cnt; - if (strncmp(argv[i], "-l", 2) == 0 && libdir_cnt > 0 && - strncmp(argv[i], "-lgcc", 5) != 0) { - - u8 found = 0; - - for (uint32_t j = 0; j < libdir_cnt && !found; j++) { - - snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], - argv[i] + 2, ".so"); - if (access(libdir_file, R_OK) != 0) { // no .so found? - - snprintf(libdir_file, sizeof(libdir_file), "%s/lib%s%s", libdirs[j], - argv[i] + 2, ".a"); - if (access(libdir_file, R_OK) == 0) { // but .a found? - - libdir_index = j; - found = 1; - if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file); - - } - - } else { - - found = 1; - if (debug) SAYF(cMGN "[D] " cRST "Found %s\n", libdir_file); - - } - - } - - } - - // is the parameter an .a AR archive? If so, unpack and check its files - if (libdir_index < libdir_cnt || - (argv[i][0] != '-' && strlen(argv[i]) > 2 && - argv[i][strlen(argv[i]) - 1] == 'a' && - argv[i][strlen(argv[i]) - 2] == '.')) { - - // This gets a bit odd. I encountered several .a files being linked and - // where the same "foo.o" was in both .a archives. llvm-link does not - // like this so we have to work around that ... - - u8 this_wd[4096], *this_ar; - u8 ar_params_cnt = 4; - u8 * ar_params[ar_params_cnt]; - u8 * file = argv[i]; - s32 pid, status; - DIR * arx; - struct dirent *dir_ent; - - if (libdir_index < libdir_cnt) file = libdir_file; - - if (ar_dir_cnt == 0) { // first archive, we setup up the basics - - ar_dir = alloc_printf("%s/.afl-%u-%u.dir", tmp_dir, getpid(), - (u32)time(NULL)); - if (mkdir(ar_dir, 0700) != 0) - FATAL("can not create temporary directory %s", ar_dir); - - } - - if (getcwd(this_wd, sizeof(this_wd)) == NULL) - FATAL("can not get the current working directory"); - if (chdir(ar_dir) != 0) - FATAL("can not chdir to temporary directory %s", ar_dir); - if (file[0] == '/') - this_ar = file; - else - this_ar = alloc_printf("%s/%s", this_wd, file); - ar_params[0] = alloc_printf("%s/%s", LLVM_BINDIR, "llvm-ar"); - ar_params[1] = "x"; - ar_params[2] = this_ar; - ar_params[3] = NULL; - - if (!be_quiet) OKF("Running ar unpacker on %s into %s", this_ar, ar_dir); - - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (uint32_t j = 0; j < ar_params_cnt; j++) - SAYF(" \"%s\"", ar_params[j]); - SAYF("\n"); - - } - - if (!(pid = fork())) { - - execvp(ar_params[0], (char **)ar_params); - FATAL("Oops, failed to execute '%s'", ar_params[0]); - - } - - if (pid < 0) FATAL("fork() failed"); - if (waitpid(pid, &status, 0) <= 0) FATAL("waitpid() failed"); - if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status)); - - if (chdir(this_wd) != 0) - FATAL("can not chdir back to our working directory %s", this_wd); - - if (!(arx = opendir(ar_dir))) FATAL("can not open directory %s", ar_dir); - - while ((dir_ent = readdir(arx)) != NULL) { - - u8 *ar_file = alloc_printf("%s/%s", ar_dir, dir_ent->d_name); - - if (dir_ent->d_name[strlen(dir_ent->d_name) - 1] == 'o' && - dir_ent->d_name[strlen(dir_ent->d_name) - 2] == '.') { - - if (passthrough || is_llvm_file(ar_file) == 0) { - - if (is_duplicate(ld_params, ld_param_cnt, ar_file) == 0) { - - ld_params[ld_param_cnt++] = ar_file; - if (debug) - SAYF(cMGN "[D] " cRST "not a LTO link file: %s\n", ar_file); - - } - - } else { - - if (is_duplicate(link_params, link_param_cnt, ar_file) == 0) { - - if (we_link == 0) { // we have to honor order ... - - ld_params[ld_param_cnt++] = final_file; - we_link = 1; - - } - - link_params[link_param_cnt++] = ar_file; - if (debug) SAYF(cMGN "[D] " cRST "is a link file: %s\n", ar_file); - - } - - } - - } else - - if (dir_ent->d_name[0] != '.' && !be_quiet) - WARNF("Unusual file found in ar archive %s: %s", argv[i], ar_file); - - } - - closedir(arx); - ar_dir_cnt++; - - continue; - - } - - if (passthrough || argv[i][0] == '-' || is_llvm_file(argv[i]) == 0) { - - // -O3 fucks up the CFG and instrumentation, so we downgrade to O2 - // which is as we want things. Lets hope this is not too different - // in the various llvm versions! - if (strncmp(argv[i], "-plugin-opt=O", 13) == 0 && - !getenv("AFL_DONT_OPTIMIZE")) - ld_params[ld_param_cnt++] = "-plugin-opt=O2"; - else - ld_params[ld_param_cnt++] = argv[i]; - - } else { - - if (we_link == 0) { // we have to honor order ... - ld_params[ld_param_cnt++] = final_file; - we_link = 1; - - } - - link_params[link_param_cnt++] = argv[i]; - - } - - } - - // if (have_lto == 0) ld_params[ld_param_cnt++] = AFL_CLANG_FLTO; // maybe we - // should not ... - ld_params[ld_param_cnt] = NULL; - link_params[link_param_cnt] = NULL; - opt_params[opt_param_cnt] = NULL; - inst_params[inst_param_cnt] = NULL; - -} - -/* clean AFL_PATH from PATH */ - -void clean_path() { - - char *tmp, *newpath = NULL, *path = getenv("PATH"); - u8 done = 0; - - if (debug) - SAYF(cMGN "[D]" cRST " old PATH=%s, AFL_PATH=%s\n", path, AFL_PATH); - - // wipe AFL paths from PATH that we set - // we added two paths so we remove the two paths - while (!done) { - - if (*path == 0) - done = 1; - else if (*path++ == ':') - done = 1; - - } - - while (*path == ':') - path++; - - // AFL_PATH could be additionally in PATH so check and remove to not call our - // 'ld' - const size_t pathlen = strlen(path); - const size_t afl_pathlen = strlen(AFL_PATH); - newpath = malloc(pathlen + 1); - if (strcmp(AFL_PATH, "/bin") != 0 && strcmp(AFL_PATH, "/usr/bin") != 0 && - afl_pathlen > 1 && (tmp = strstr(path, AFL_PATH)) != NULL && // it exists - (tmp == path || - (tmp > path && - tmp[-1] == ':')) && // either starts with it or has a colon before - (tmp + afl_pathlen == path + pathlen || - (tmp + afl_pathlen < - path + (pathlen && tmp[afl_pathlen] == - ':')) // end with it or has a colon at the end - )) { - - int one_colon = 1; - - if (tmp > path) { - - memcpy(newpath, path, tmp - path); - newpath[tmp - path - 1] = 0; // remove ':' - one_colon = 0; - - } - - if (tmp + afl_pathlen < path + pathlen) tmp += afl_pathlen + one_colon; - - setenv("PATH", newpath, 1); - - } else - - setenv("PATH", path, 1); - - if (debug) SAYF(cMGN "[D]" cRST " new PATH=%s\n", getenv("PATH")); - free(newpath); - -} - -/* Main entry point */ - -int main(int argc, char **argv) { - - s32 pid, i; - int status; - u8 *ptr, exe[4096], exe2[4096], proc[32], val[2] = " "; - int have_afl_ld_caller = 0; - - if (isatty(2) && !getenv("AFL_QUIET") && !getenv("AFL_DEBUG")) { - - if (getenv("AFL_LD") != NULL) - SAYF(cCYA "afl-ld" VERSION cRST - " by Marc \"vanHauser\" Heuse (level %d)\n", - have_afl_ld_caller); - - } else - - be_quiet = 1; - - if (getenv("AFL_DEBUG") != NULL) debug = 1; - if (getenv("AFL_PATH") != NULL) afl_path = getenv("AFL_PATH"); - if (getenv("AFL_LD_PASSTHROUGH") != NULL) passthrough = 1; - if (getenv("AFL_REAL_LD") != NULL) real_ld = getenv("AFL_REAL_LD"); - if (real_ld == NULL || strlen(real_ld) < 2) real_ld = "/bin/ld"; - if (real_ld != NULL && real_ld[0] != '/') - real_ld = alloc_printf("/bin/%s", real_ld); - - if ((ptr = getenv("AFL_LD_CALLER")) != NULL) have_afl_ld_caller = atoi(ptr); - val[0] = 0x31 + have_afl_ld_caller; - setenv("AFL_LD_CALLER", val, 1); - - if (debug) { - - SAYF(cMGN "[D] " cRST - "AFL_LD=%s, set AFL_LD_CALLER=%s, have_afl_ld_caller=%d, " - "real_ld=%s\n", - getenv("AFL_LD"), val, have_afl_ld_caller, real_ld); - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < argc; i++) - SAYF(" \"%s\"", argv[i]); - SAYF("\n"); - - } - - sprintf(proc, "/proc/%d/exe", getpid()); - if (readlink(proc, exe, sizeof(exe) - 1) > 0) { - - if (readlink(real_ld, exe2, sizeof(exe2) - 1) < 1) exe2[0] = 0; - exe[sizeof(exe) - 1] = 0; - exe[sizeof(exe2) - 1] = 0; - if (strcmp(exe, real_ld) == 0 || strcmp(exe, exe2) == 0) - PFATAL(cLRD "[!] " cRST - "Error: real 'ld' path points to afl-ld, set AFL_REAL_LD to " - "the real 'ld' program!"); - - } - - if (have_afl_ld_caller > 1) - PFATAL(cLRD "[!] " cRST - "Error: afl-ld calls itself in a loop, set AFL_REAL_LD to the " - "real 'ld' program!"); - - if (argc < 2) { - - SAYF( - "\n" - "This is a helper application for afl-fuzz. It is a wrapper around GNU " - "'ld',\n" - "executed by the toolchain whenever using " - "afl-clang-lto/afl-clang-lto++.\n" - "You probably don't want to run this program directly.\n\n" - - "Environment variables:\n" - " AFL_LD_PASSTHROUGH do not link+optimize == no instrumentation\n" - " AFL_REAL_LD point to the real ld if necessary\n" - - "\nafl-ld was compiled with the fixed real 'ld' path of %s and the " - "clang " - "bin path of %s\n\n", - real_ld, LLVM_BINDIR); - - exit(1); - - } - - if (getenv("AFL_LD") == NULL) { - - /* if someone install clang/ld into the same directory as afl++ then - they are out of luck ... */ - - if (have_afl_ld_caller == 1) { clean_path(); } - - if (real_ld != NULL && strlen(real_ld) > 1) execvp(real_ld, argv); - execvp("ld", argv); // fallback - PFATAL("Oops, failed to execute 'ld' - check your PATH"); - - } - - atexit(at_exit_handler); // ensure to wipe temp files if things fail - - edit_params(argc, argv); // here most of the magic happens :-) - - if (debug) - SAYF(cMGN "[D] " cRST - "param counts: ar:%u lib:%u ld:%u link:%u opt:%u instr:%u\n", - ar_dir_cnt, libdir_cnt, ld_param_cnt, link_param_cnt, opt_param_cnt, - inst_param_cnt); - - if (!just_version) { - - if (we_link == 0) { - - if (!getenv("AFL_QUIET")) - WARNF("No LTO input file found, cannot instrument!"); - - } else { - - /* first we link all files */ - if (!be_quiet) OKF("Running bitcode linker, creating %s", linked_file); - - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < link_param_cnt; i++) - SAYF(" \"%s\"", link_params[i]); - SAYF("\n"); - - } - - if (!(pid = fork())) { - - execvp(link_params[0], (char **)link_params); - FATAL("Oops, failed to execute '%s'", link_params[0]); - - } - - if (pid < 0) PFATAL("fork() failed"); - if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); - if (WEXITSTATUS(status) != 0) { - - SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD - "\n[-] PROGRAM ABORT : " cRST); - SAYF( - "llvm-link failed! Probable causes:\n\n" - " #1 If the error is \"linking globals named '...': symbol " - "multiply defined\"\n" - " then there is nothing we can do - llvm-link is missing an " - "important feature\n\n" - " #2 If the error is \"expected top-level entity\" and then " - "binary output, this\n" - " is because the same file is present in different .a archives " - "in different\n" - " formats. This can be fixed by manual doing the steps afl-ld " - "is doing but\n" - " programmatically - sorry!\n\n"); - exit(WEXITSTATUS(status)); - - } - - /* then we perform an optimization on the collected objects files */ - if (!be_quiet) - OKF("Performing optimization via opt, creating %s", modified_file); - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < opt_param_cnt; i++) - SAYF(" \"%s\"", opt_params[i]); - SAYF("\n"); - - } - - if (!(pid = fork())) { - - execvp(opt_params[0], (char **)opt_params); - FATAL("Oops, failed to execute '%s'", opt_params[0]); - - } - - if (pid < 0) PFATAL("fork() failed"); - if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); - if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status)); - - /* then we run the instrumentation through the optimizer */ - if (!be_quiet) - OKF("Performing instrumentation via opt, creating %s", final_file); - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < inst_param_cnt; i++) - SAYF(" \"%s\"", inst_params[i]); - SAYF("\n"); - - } - - if (!(pid = fork())) { - - execvp(inst_params[0], (char **)inst_params); - FATAL("Oops, failed to execute '%s'", inst_params[0]); - - } - - if (pid < 0) PFATAL("fork() failed"); - if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); - if (WEXITSTATUS(status) != 0) exit(WEXITSTATUS(status)); - - } - - /* next step - run the linker! :-) */ - - } - - if (!be_quiet) OKF("Running real linker %s", real_ld); - if (debug) { - - SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); - for (i = 0; i < ld_param_cnt; i++) - SAYF(" \"%s\"", ld_params[i]); - SAYF("\n"); - - } - - if (!(pid = fork())) { - - clean_path(); - - unsetenv("AFL_LD"); - - if (strlen(real_ld) > 1) execvp(real_ld, (char **)ld_params); - execvp("ld", (char **)ld_params); // fallback - FATAL("Oops, failed to execute 'ld' - check your PATH"); - - } - - if (pid < 0) PFATAL("fork() failed"); - - if (waitpid(pid, &status, 0) <= 0) PFATAL("waitpid() failed"); - if (debug) SAYF(cMGN "[D] " cRST "linker result: %d\n", status); - - if (!just_version) { - - if (!getenv("AFL_KEEP_ASSEMBLY")) { - - if (linked_file) { - - unlink(linked_file); - linked_file = NULL; - - } - - if (modified_file) { - - unlink(modified_file); - modified_file = NULL; - - } - - if (final_file) { - - unlink(final_file); - final_file = NULL; - - } - - if (ar_dir != NULL) { - - wipe_directory(ar_dir); - ar_dir = NULL; - - } - - } else { - - if (!be_quiet) { - - SAYF( - "[!] afl-ld: keeping link file %s, optimized bitcode %s and " - "instrumented bitcode %s", - linked_file, modified_file, final_file); - if (ar_dir_cnt > 0 && ar_dir) - SAYF(" and ar archive unpack directory %s", ar_dir); - SAYF("\n"); - - } - - } - - if (status == 0) { - - if (!be_quiet) OKF("Linker was successful"); - - } else { - - SAYF(cLRD "[-] " cRST - "Linker failed, please investigate and send a bug report. Most " - "likely an 'ld' option is incompatible with %s. Try " - "AFL_KEEP_ASSEMBLY=1 and AFL_DEBUG=1 for replaying.\n", - AFL_CLANG_FLTO); - - } - - } - - exit(WEXITSTATUS(status)); - -} - diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 4bc16f17..2a9b17b2 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -378,7 +378,8 @@ bool AFLLTOPass::runOnModule(Module &M) { M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id); - AFLFinalLoc->setAlignment(4); + MaybeAlign Align = MaybeAlign(4); + AFLFinalLoc->setAlignment(Align); AFLFinalLoc->setInitializer(const_loc); } @@ -423,5 +424,5 @@ static RegisterPass X("afl-lto", "afl++ LTO instrumentation pass", false, false); static RegisterStandardPasses RegisterAFLLTOPass( - PassManagerBuilder::EP_OptimizerLast, registerAFLLTOPass); + PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerAFLLTOPass); -- cgit 1.4.1 From b485b7a25262fa9151c5b6792ba3508f6474769e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 9 Apr 2020 11:49:40 +0200 Subject: fix compilers for empty AFL_CC/AFL_CXX env --- docs/Changelog.md | 4 +++- gcc_plugin/afl-gcc-fast.c | 4 ++-- llvm_mode/GNUmakefile | 13 +------------ llvm_mode/afl-clang-fast.c | 4 ++-- src/afl-gcc.c | 10 +++++----- test/test.sh | 2 ++ 6 files changed, 15 insertions(+), 22 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 18f38551..0ec330a7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,7 +10,9 @@ sending a mail to . ### Version ++2.63d (development): - - ... + - LTO mode now requires llvm11 - but compiles all targets! :) + - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed + (this bug is in vanilla afl too) ### Version ++2.63c (release): diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c index fbda08b6..8953c523 100644 --- a/gcc_plugin/afl-gcc-fast.c +++ b/gcc_plugin/afl-gcc-fast.c @@ -121,12 +121,12 @@ static void edit_params(u32 argc, char **argv) { if (!strcmp(name, "afl-g++-fast")) { u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)AFL_GCC_CXX; } else { u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)AFL_GCC_CC; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)AFL_GCC_CC; } diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index ce60dd1c..7432b061 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -188,7 +188,7 @@ ifeq "$(TEST_MMAP)" "1" LDFLAGS += -lrt endif - PROGS = ../afl-clang-fast ../afl-ld ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so + PROGS = ../afl-clang-fast ../afl-llvm-pass.so ../afl-llvm-lto-whitelist.so ../afl-llvm-lto-instrumentation.so ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so ../cmplog-routines-pass.so ../cmplog-instructions-pass.so # If prerequisites are not given, warn, do not build anything, and exit with code 0 ifeq "$(LLVMVER)" "" @@ -256,17 +256,6 @@ ifeq "$(LLVM_LTO)" "1" endif endif -../afl-ld: afl-ld.c -ifneq "$(AFL_CLANG_FLTO)" "" -ifeq "$(LLVM_LTO)" "1" - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) - ln -sf afl-ld ../ld - @rm -f .test-instr - @-export AFL_QUIET=1 AFL_PATH=.. PATH="..:$(PATH)" ; ../afl-clang-lto -o .test-instr ../test-instr.c && echo "[+] afl-clang-lto seems to work fine :)" || echo "[!] WARNING: clang seems to have a hardcoded "'/bin/ld'" - check README.lto" - @rm -f .test-instr -endif -endif - ../libLLVMInsTrim.so: LLVMInsTrim.so.cc MarkNodes.cc | test_deps -$(CXX) $(CLANG_CFL) -DLLVMInsTrim_EXPORTS -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< MarkNodes.cc -o $@ $(CLANG_LFL) diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 9d8ebdec..26ee0bab 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -185,7 +185,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", LLVM_BINDIR); else sprintf(llvm_fullpath, "clang++"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; } else { @@ -194,7 +194,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR); else sprintf(llvm_fullpath, "clang"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)llvm_fullpath; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath; } diff --git a/src/afl-gcc.c b/src/afl-gcc.c index b0153b49..32cd36cb 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -142,12 +142,12 @@ static void edit_params(u32 argc, char **argv) { if (!strcmp(name, "afl-clang++")) { u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"clang++"; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"clang++"; } else { u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"clang"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"clang"; } @@ -187,17 +187,17 @@ static void edit_params(u32 argc, char **argv) { if (!strcmp(name, "afl-g++")) { u8 *alt_cxx = getenv("AFL_CXX"); - cc_params[0] = alt_cxx ? alt_cxx : (u8 *)"g++"; + cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)"g++"; } else if (!strcmp(name, "afl-gcj")) { u8 *alt_cc = getenv("AFL_GCJ"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcj"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcj"; } else { u8 *alt_cc = getenv("AFL_CC"); - cc_params[0] = alt_cc ? alt_cc : (u8 *)"gcc"; + cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)"gcc"; } diff --git a/test/test.sh b/test/test.sh index 0666ca36..c673337e 100755 --- a/test/test.sh +++ b/test/test.sh @@ -581,6 +581,8 @@ test -e ../afl-gcc-fast -a -e ../afl-gcc-rt.o && { INCOMPLETE=1 } +test -z "$AFL_CC" && unset AFL_CC + $ECHO "$BLUE[*] Testing: shared library extensions" cc $CFLAGS -o test-compcov test-compcov.c > /dev/null 2>&1 test -e ../libtokencap.so && { -- cgit 1.4.1 From 3a509c61689112cc321c4c78f058014abff66c8a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 10 Apr 2020 22:33:11 +0200 Subject: LTO optimization, variable map size, autodictionary (#307) * lto module clean-up * step 1/3 * step 1/3 completed * if tmp is ever made non-static * parts 2 and 3 - autodictionary is complete * variable map_size support * variable map size: changed overlooked functions * remove debug for autodict * 64 bit alignment of map size * fix review comments * force 64 bit alignment on both sides * typo --- docs/env_variables.md | 11 +- gcc_plugin/afl-gcc-rt.o.c | 4 +- include/afl-fuzz.h | 22 +- include/config.h | 14 +- include/forkserver.h | 6 + llvm_mode/GNUmakefile | 3 +- llvm_mode/README.lto.md | 41 ++-- llvm_mode/afl-clang-fast.c | 3 + llvm_mode/afl-llvm-lto-instrumentation.so.cc | 330 +++++++++++++++++++++++++-- llvm_mode/afl-llvm-rt.o.c | 170 ++++++++++++-- qemu_mode/patches/afl-qemu-cpu-inl.h | 2 +- src/afl-common.c | 1 + src/afl-forkserver.c | 96 +++++++- src/afl-fuzz-bitmap.c | 61 +++-- src/afl-fuzz-cmplog.c | 6 +- src/afl-fuzz-extras.c | 10 +- src/afl-fuzz-init.c | 4 +- src/afl-fuzz-mutators.c | 7 +- src/afl-fuzz-one.c | 16 +- src/afl-fuzz-queue.c | 19 +- src/afl-fuzz-redqueen.c | 14 +- src/afl-fuzz-run.c | 27 +-- src/afl-fuzz-state.c | 4 + src/afl-fuzz-stats.c | 11 +- src/afl-tmin.c | 4 +- 25 files changed, 726 insertions(+), 160 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index cd002145..7890da35 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -111,10 +111,15 @@ Then there are a few specific features that are only available in llvm_mode: instrumentation which is 100% collision free (collisions are a big issue in afl and afl-like instrumentations). This is performed by using afl-clang-lto/afl-clang-lto++ instead of afl-clang-fast, but is only - built if LLVM 9 or newer is used. + built if LLVM 11 or newer is used. - None of these options are necessary to be used and are rather for manual - use (which only ever the author of this LTO implementation will use ;-) + - AFL_LLVM_LTO_AUTODICTIONARY will generate a dictionary in the target + binary based on string compare and memory compare functions. + afl-fuzz will automatically get these transmitted when starting to + fuzz. + + None of the following options are necessary to be used and are rather for + manual use (which only ever the author of this LTO implementation will use). These are used if several seperated instrumentation are performed which are then later combined. diff --git a/gcc_plugin/afl-gcc-rt.o.c b/gcc_plugin/afl-gcc-rt.o.c index 30606150..b157b50f 100644 --- a/gcc_plugin/afl-gcc-rt.o.c +++ b/gcc_plugin/afl-gcc-rt.o.c @@ -138,8 +138,8 @@ static void __afl_map_shm(void) { static void __afl_start_forkserver(void) { - static u8 tmp[4]; - s32 child_pid; + u8 tmp[4] = {0, 0, 0, 0}; + s32 child_pid; u8 child_stopped = 0; diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 56135d0e..edda81e1 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -577,7 +577,9 @@ typedef struct afl_state { u32 document_counter; #endif - /* statis file */ + void *maybe_add_auto; + + /* statistics file */ double last_bitmap_cvg, last_stability, last_eps; /* plot file saves from last run */ @@ -840,18 +842,18 @@ u32 calculate_score(afl_state_t *, struct queue_entry *); void read_bitmap(afl_state_t *, u8 *); void write_bitmap(afl_state_t *); -u32 count_bits(u8 *); -u32 count_bytes(u8 *); -u32 count_non_255_bytes(u8 *); +u32 count_bits(afl_state_t *, u8 *); +u32 count_bytes(afl_state_t *, u8 *); +u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 -void simplify_trace(u64 *); -void classify_counts(u64 *); +void simplify_trace(afl_state_t *, u64 *); +void classify_counts(afl_state_t *, u64 *); #else -void simplify_trace(u32 *); -void classify_counts(u32 *); +void simplify_trace(afl_state_t *, u32 *); +void classify_counts(afl_state_t *, u32 *); #endif void init_count_class16(void); -void minimize_bits(u8 *, u8 *); +void minimize_bits(afl_state_t *, u8 *, u8 *); #ifndef SIMPLE_FILES u8 *describe_op(afl_state_t *, u8); #endif @@ -862,7 +864,7 @@ u8 has_new_bits(afl_state_t *, u8 *); void load_extras_file(afl_state_t *, u8 *, u32 *, u32 *, u32); void load_extras(afl_state_t *, u8 *); -void maybe_add_auto(afl_state_t *, u8 *, u32); +void maybe_add_auto(void *, u8 *, u32); void save_auto(afl_state_t *); void load_auto(afl_state_t *); void destroy_extras(afl_state_t *); diff --git a/include/config.h b/include/config.h index cf73772f..f0274fd3 100644 --- a/include/config.h +++ b/include/config.h @@ -201,8 +201,8 @@ (first value), and to keep in memory as candidates. The latter should be much higher than the former. */ -#define USE_AUTO_EXTRAS 50 -#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) +#define USE_AUTO_EXTRAS 128 +#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 64) /* Scaling factor for the effector map used to skip some of the more expensive deterministic steps. The actual divisor is set to @@ -400,5 +400,15 @@ #endif #endif /* __APPLE__ || __FreeBSD__ || __OpenBSD__ */ +/* Extended forkserver option values */ + +#define FS_OPT_ENABLED 0x8f000001 +#define FS_OPT_MAPSIZE 0x40000000 +#define FS_OPT_SNAPSHOT 0x20000000 +#define FS_OPT_AUTODICT 0x10000000 +#define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) +#define FS_OPT_SET_MAPSIZE(x) \ + (x <= 1 || x > MAP_SIZE || x > 0x1000000 ? 0 : ((x - 1) << 1)) + #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/forkserver.h b/include/forkserver.h index 4110df7d..7470dbbc 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -51,6 +51,8 @@ typedef struct afl_forkserver { fsrv_st_fd; /* Fork server status pipe (read) */ u32 exec_tmout; /* Configurable exec timeout (ms) */ + u32 map_size; /* map size used by the target */ + u32 snapshot; /* is snapshot feature used */ u64 mem_limit; /* Memory cap for child (MB) */ u8 *out_file, /* File to fuzz, if any */ @@ -64,6 +66,10 @@ typedef struct afl_forkserver { u32 prev_timed_out; /* if prev forkserver run timed out */ + u8 *function_opt; /* for autodictionary: afl ptr */ + + void (*function_ptr)(void *afl_tmp, u8 *mem, u32 len); + } afl_forkserver_t; void afl_fsrv_init(afl_forkserver_t *fsrv); diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 7432b061..b176a24f 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -273,6 +273,7 @@ endif ../afl-llvm-lto-instrumentation.so: afl-llvm-lto-instrumentation.so.cc ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) + $(CC) $(CFLAGS) -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o endif # laf @@ -318,7 +319,7 @@ all_done: test_build install: all install -d -m 755 $${DESTDIR}$(BIN_PATH) $${DESTDIR}$(HELPER_PATH) $${DESTDIR}$(DOC_PATH) $${DESTDIR}$(MISC_PATH) if [ -f ../afl-clang-fast -a -f ../libLLVMInsTrim.so -a -f ../afl-llvm-rt.o ]; then set -e; install -m 755 ../afl-clang-fast $${DESTDIR}$(BIN_PATH); ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-fast++; install -m 755 ../libLLVMInsTrim.so ../afl-llvm-pass.so ../afl-llvm-rt.o $${DESTDIR}$(HELPER_PATH); fi - if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so $${DESTDIR}$(HELPER_PATH); install -m 755 ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi + if [ -f ../afl-clang-lto ]; then set -e; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-clang-fast $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ../afl-llvm-lto-instrumentation.so ../afl-llvm-rt-lto.o ../afl-llvm-lto-whitelist.so $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-32.o ]; then set -e; install -m 755 ../afl-llvm-rt-32.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../afl-llvm-rt-64.o ]; then set -e; install -m 755 ../afl-llvm-rt-64.o $${DESTDIR}$(HELPER_PATH); fi if [ -f ../compare-transform-pass.so ]; then set -e; install -m 755 ../compare-transform-pass.so $${DESTDIR}$(HELPER_PATH); fi diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index a3c7ddc3..48d0e36c 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -12,6 +12,8 @@ This version requires a current llvm 11 compiled from the github master. 3. It only works with llvm 11 (current github master state) +4. AUTODICTIONARY feature! see below + ## Introduction and problem description A big issue with how afl/afl++ works is that the basic block IDs that are @@ -33,33 +35,22 @@ and many dead ends until we got to this: * Our compiler (afl-clang-lto/afl-clang-lto++) takes care of setting the correct LTO options and runs our own afl-ld linker instead of the system linker - * Our linker collects all LTO files to link and instruments them so that + * The LLVM linker collects all LTO files to link and instruments them so that we have non-colliding edge overage * We use a new (for afl) edge coverage - which is the same as in llvm -fsanitize=coverage edge coverage mode :) - * after inserting our instrumentation in all interesting edges we link - all parts of the program together to our executable The result: - * 10-15% speed gain compared to llvm_mode + * 10-20% speed gain compared to llvm_mode * guaranteed non-colliding edge coverage :-) * The compile time especially for libraries can be longer Example build output from a libtiff build: ``` -/bin/bash ../libtool --tag=CC --mode=link afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/libtiff.la ../port/libport.la -llzma -ljbig -ljpeg -lz -lm libtool: link: afl-clang-lto -g -O2 -Wall -W -o thumbnail thumbnail.o ../libtiff/.libs/libtiff.a ../port/.libs/libport.a -llzma -ljbig -ljpeg -lz -lm -afl-clang-lto++2.62d by Marc "vanHauser" Heuse -afl-ld++2.62d by Marc "vanHauser" Heuse (level 0) -[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../libtiff/.libs/libtiff.a into /tmp/.afl-3914343-1583339800.dir -[+] Running ar unpacker on /prg/tests/lto/tiff-4.0.4/tools/../port/.libs/libport.a into /tmp/.afl-3914343-1583339800.dir -[+] Running bitcode linker, creating /tmp/.afl-3914343-1583339800-1.ll -[+] Performing optimization via opt, creating /tmp/.afl-3914343-1583339800-2.bc -[+] Performing instrumentation via opt, creating /tmp/.afl-3914343-1583339800-3.bc -afl-llvm-lto++2.62d by Marc "vanHauser" Heuse -[+] Instrumented 15833 locations with no collisions (on average 1767 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). -[+] Running real linker /bin/x86_64-linux-gnu-ld -[+] Linker was successful +afl-clang-lto++2.63d by Marc "vanHauser" Heuse in mode LTO +afl-llvm-lto++2.63d by Marc "vanHauser" Heuse +[+] Instrumented 11836 locations with no collisions (on average 1007 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). ``` ## Building llvm 11 @@ -70,8 +61,8 @@ $ git clone https://github.com/llvm/llvm-project $ cd llvm-project $ mkdir build $ cd build -$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ -$ make +$ cmake -DLLVM_ENABLE_PROJECTS='clang;clang-tools-extra;compiler-rt;libclc;libcxx;libcxxabi;libunwind;lld' -DCMAKE_BUILD_TYPE=Release -DLLVM_BINUTILS_INCDIR=/usr/include/ ../llvm/ +$ make -j $(nproc) $ export PATH=`pwd`/bin:$PATH $ export LLVM_CONFIG=`pwd`/bin/llcm-config $ cd /path/to/AFLplusplus/ @@ -96,6 +87,13 @@ CC=afl-clang-lto CXX=afl-clang-lto++ ./configure make ``` +## AUTODICTIONARY feature + +Setting `AFL_LLVM_LTO_AUTODICTIONARY` will generate a dictionary in the +target binary based on string compare and memory compare functions. +afl-fuzz will automatically get these transmitted when starting to fuzz. +This improves coverage on a lot of targets. + ## Potential issues ### compiling libraries fails @@ -121,11 +119,8 @@ Please report issues at: ## Upcoming Work -1. Currently the LTO whitelist feature does not allow to not instrument main, start and init functions -2. Modify the forkserver + afl-fuzz so that only the necessary map size is - loaded and used - and communicated to afl-fuzz too. - Result: faster fork in the target and faster map analysis in afl-fuzz - => more speed :-) +1. Currently the LTO whitelist feature does not allow to not instrument main, + start and init functions ## History diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 26ee0bab..cdb22cb9 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -477,6 +477,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } + if (instrument_mode == INSTRUMENT_LTO) + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-lto.o", obj_path); + #ifndef __ANDROID__ switch (bit_mode) { diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 93968984..f387e79c 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -38,17 +38,24 @@ #include #include "llvm/Config/llvm-config.h" +#include "llvm/ADT/Statistic.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Module.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Verifier.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#include "llvm/IR/DebugInfo.h" -#include "llvm/IR/CFG.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/Pass.h" + +#include using namespace llvm; @@ -145,7 +152,7 @@ class AFLLTOPass : public ModulePass { bool runOnModule(Module &M) override; protected: - int afl_global_id = 1, debug = 0; + int afl_global_id = 1, debug = 0, autodictionary = 0; uint32_t be_quiet = 0, inst_blocks = 0, inst_funcs = 0, total_instr = 0; }; @@ -154,7 +161,9 @@ class AFLLTOPass : public ModulePass { bool AFLLTOPass::runOnModule(Module &M) { - LLVMContext &C = M.getContext(); + LLVMContext & C = M.getContext(); + std::vector dictionary; + std::vector calls; IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -172,6 +181,10 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + if (getenv("AFL_LLVM_AUTODICTIONARY") || + getenv("AFL_LLVM_LTO_AUTODICTIONARY")) + autodictionary = 1; + /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ @@ -193,6 +206,110 @@ bool AFLLTOPass::runOnModule(Module &M) { std::vector InsBlocks; + if (autodictionary) { + + for (auto &BB : F) { + + for (auto &IN : BB) { + + CallInst *callInst = nullptr; + + if ((callInst = dyn_cast(&IN))) { + + bool isStrcmp = true; + bool isMemcmp = true; + bool isStrncmp = true; + bool isStrcasecmp = true; + bool isStrncasecmp = true; + + Function *Callee = callInst->getCalledFunction(); + if (!Callee) continue; + if (callInst->getCallingConv() != llvm::CallingConv::C) continue; + StringRef FuncName = Callee->getName(); + isStrcmp &= !FuncName.compare(StringRef("strcmp")); + isMemcmp &= !FuncName.compare(StringRef("memcmp")); + isStrncmp &= !FuncName.compare(StringRef("strncmp")); + isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp")); + isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp")); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp) + continue; + + /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function + * prototype */ + FunctionType *FT = Callee->getFunctionType(); + + isStrcmp &= FT->getNumParams() == 2 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()); + isStrcasecmp &= FT->getNumParams() == 2 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()); + isMemcmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0)->isPointerTy() && + FT->getParamType(1)->isPointerTy() && + FT->getParamType(2)->isIntegerTy(); + isStrncmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + isStrncasecmp &= FT->getNumParams() == 3 && + FT->getReturnType()->isIntegerTy(32) && + FT->getParamType(0) == FT->getParamType(1) && + FT->getParamType(0) == + IntegerType::getInt8PtrTy(M.getContext()) && + FT->getParamType(2)->isIntegerTy(); + + if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && + !isStrncasecmp) + continue; + + /* is a str{n,}{case,}cmp/memcmp, check if we have + * str{case,}cmp(x, "const") or str{case,}cmp("const", x) + * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..) + * memcmp(x, "const", ..) or memcmp("const", x, ..) */ + Value *Str1P = callInst->getArgOperand(0), + *Str2P = callInst->getArgOperand(1); + StringRef Str1, Str2; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + bool HasStr2 = getConstantStringInfo(Str2P, Str2); + + /* handle cases of one string is const, one string is variable */ + if (!(HasStr1 ^ HasStr2)) continue; + + if (isMemcmp || isStrncmp || isStrncasecmp) { + + /* check if third operand is a constant integer + * strlen("constStr") and sizeof() are treated as constant */ + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast(op2); + if (!ilen) continue; + /* final precaution: if size of compare is larger than constant + * string skip it*/ + uint64_t literalLength = + HasStr1 ? GetStringLength(Str1P) : GetStringLength(Str2P); + if (literalLength < ilen->getZExtValue()) continue; + + } + + calls.push_back(callInst); + + } + + } + + } + + } + for (auto &BB : F) { uint32_t succ = 0; @@ -282,32 +399,201 @@ bool AFLLTOPass::runOnModule(Module &M) { } + // save highest location ID to global variable + // do this after each function to fail faster + if (afl_global_id > MAP_SIZE) { + + uint32_t pow2map = 1, map = afl_global_id; + while ((map = map >> 1)) + pow2map++; + FATAL( + "We have %u blocks to instrument but the map size is only %u! Edit " + "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " + "afl-fuzz and llvm_mode.", + afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map); + + } + } - // save highest location ID to global variable + if (calls.size()) { - if (afl_global_id > MAP_SIZE) { + for (auto &callInst : calls) { - uint32_t pow2map = 1, map = afl_global_id; - while ((map = map >> 1)) - pow2map++; - FATAL( - "We have %u blocks to instrument but the map size is only %u! Edit " - "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " - "afl-fuzz and llvm_mode.", - afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map); + Value *Str1P = callInst->getArgOperand(0), + *Str2P = callInst->getArgOperand(1); + StringRef Str1, Str2, ConstStr; + std::string TmpConstStr; + Value * VarStr; + bool HasStr1 = getConstantStringInfo(Str1P, Str1); + getConstantStringInfo(Str2P, Str2); + uint64_t constLen, sizedLen; + bool isMemcmp = !callInst->getCalledFunction()->getName().compare( + StringRef("memcmp")); + bool isSizedcmp = isMemcmp || + !callInst->getCalledFunction()->getName().compare( + StringRef("strncmp")) || + !callInst->getCalledFunction()->getName().compare( + StringRef("strncasecmp")); + + if (isSizedcmp) { + + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast(op2); + sizedLen = ilen->getZExtValue(); + + } else { + + sizedLen = 0; + + } + + if (HasStr1) { + + TmpConstStr = Str1.str(); + VarStr = Str2P; + constLen = isMemcmp ? sizedLen : GetStringLength(Str1P); + + } else { + + TmpConstStr = Str2.str(); + VarStr = Str1P; + constLen = isMemcmp ? sizedLen : GetStringLength(Str2P); + + } + + /* properly handle zero terminated C strings by adding the terminating 0 + * to the StringRef (in comparison to std::string a StringRef has built-in + * runtime bounds checking, which makes debugging easier) */ + TmpConstStr.append("\0", 1); + ConstStr = StringRef(TmpConstStr); + + if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; } + + /* + if (!be_quiet) + errs() << callInst->getCalledFunction()->getName() << ": len " + << constLen << ": " << ConstStr << "\n"; + */ + + if (constLen && constLen < MAX_DICT_FILE) + dictionary.push_back(ConstStr.str().substr(0, constLen)); + + } } - if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { + if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) { + + // yes we could create our own function, insert it into ctors ... + // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o - GlobalVariable *AFLFinalLoc = new GlobalVariable( - M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", 0, - GlobalVariable::GeneralDynamicTLSModel, 0, false); - ConstantInt *const_loc = ConstantInt::get(Int32Ty, afl_global_id); - MaybeAlign Align = MaybeAlign(4); - AFLFinalLoc->setAlignment(Align); - AFLFinalLoc->setInitializer(const_loc); + Function *f = M.getFunction("__afl_auto_init_globals"); + + if (!f) { + + fprintf(stderr, + "Error: init function could not be found (this hould not " + "happen)\n"); + exit(-1); + + } + + BasicBlock *bb = &f->getEntryBlock(); + if (!bb) { + + fprintf(stderr, + "Error: init function does not have an EntryBlock (this should " + "not happen)\n"); + exit(-1); + + } + + BasicBlock::iterator IP = bb->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + + if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) { + + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, "__afl_final_loc", + 0, GlobalVariable::GeneralDynamicTLSModel, 0, false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, (((afl_global_id + 8) >> 3) << 3)); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + if (dictionary.size()) { + + size_t memlen = 0, count = 0, offset = 0; + char * ptr; + + for (auto token : dictionary) { + + memlen += token.length(); + count++; + + } + + if (!be_quiet) printf("AUTODICTIONARY: %lu strings found\n", count); + + if (count) { + + if ((ptr = (char *)malloc(memlen + count)) == NULL) { + + fprintf(stderr, "Error: malloc for %lu bytes failed!\n", + memlen + count); + exit(-1); + + } + + for (auto token : dictionary) { + + if (offset + token.length() < 0xfffff0) { + + ptr[offset++] = (uint8_t)token.length(); + memcpy(ptr + offset, token.c_str(), token.length()); + offset += token.length(); + + } + + } + + GlobalVariable *AFLDictionaryLen = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, + "__afl_dictionary_len", 0, GlobalVariable::GeneralDynamicTLSModel, + 0, false); + ConstantInt *const_len = ConstantInt::get(Int32Ty, offset); + StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen); + StoreDictLen->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + ArrayType *ArrayTy = ArrayType::get(IntegerType::get(C, 8), offset); + GlobalVariable *AFLInternalDictionary = new GlobalVariable( + M, ArrayTy, true, GlobalValue::ExternalLinkage, + ConstantDataArray::get(C, + *(new ArrayRef((char *)ptr, offset))), + "__afl_internal_dictionary", 0, + GlobalVariable::GeneralDynamicTLSModel, 0, false); + AFLInternalDictionary->setInitializer(ConstantDataArray::get( + C, *(new ArrayRef((char *)ptr, offset)))); + AFLInternalDictionary->setConstant(true); + + GlobalVariable *AFLDictionary = new GlobalVariable( + M, PointerType::get(Int8Ty, 0), false, GlobalValue::ExternalLinkage, + 0, "__afl_dictionary"); + + Value *AFLDictOff = IRB.CreateGEP(AFLInternalDictionary, Zero); + Value *AFLDictPtr = + IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Ty, 0)); + StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary); + StoreDict->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 3651fd97..cbc4648d 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -50,11 +50,7 @@ Basically, we need to make sure that the forkserver is initialized after the LLVM-generated runtime initialization pass, not before. */ -#ifdef USE_TRACE_PC #define CONST_PRIO 5 -#else -#define CONST_PRIO 0 -#endif /* ^USE_TRACE_PC */ #include #include @@ -65,17 +61,20 @@ u8 __afl_area_initial[MAP_SIZE]; u8 *__afl_area_ptr = __afl_area_initial; +u8 *__afl_dictionary; #ifdef __ANDROID__ PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; u32 __afl_final_loc; u32 __afl_prev_ctx; u32 __afl_cmp_counter; +u32 __afl_dictionary_len; #else __thread PREV_LOC_T __afl_prev_loc[NGRAM_SIZE_MAX]; __thread u32 __afl_final_loc; __thread u32 __afl_prev_ctx; __thread u32 __afl_cmp_counter; +__thread u32 __afl_dictionary_len; #endif struct cmp_map *__afl_cmp_map; @@ -100,6 +99,10 @@ static void __afl_map_shm(void) { const char * shm_file_path = id_str; int shm_fd = -1; unsigned char *shm_base = NULL; + unsigned int map_size = MAP_SIZE + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) map_size = + __afl_final_loc; /* create the shared memory segment as if it was a file */ shm_fd = shm_open(shm_file_path, O_RDWR, 0600); @@ -111,7 +114,7 @@ static void __afl_map_shm(void) { } /* map the shared memory segment to the address space of the process */ - shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + shm_base = mmap(0, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shm_base == MAP_FAILED) { close(shm_fd); @@ -187,8 +190,15 @@ static void __afl_map_shm(void) { #ifdef __linux__ static void __afl_start_snapshots(void) { - static u8 tmp[4]; + static u8 tmp[4] = {0, 0, 0, 0}; s32 child_pid; + u32 status = 0; + u32 map_size = MAP_SIZE; + u32 already_read_first = 0; + u32 was_killed; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; u8 child_stopped = 0; @@ -197,16 +207,74 @@ static void __afl_start_snapshots(void) { /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ + status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT); + if (map_size <= 0x1000000) + status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; + memcpy(tmp, &status, 4); + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (__afl_dictionary_len > 0 && __afl_dictionary) { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == + (FS_OPT_ENABLED | FS_OPT_AUTODICT)) { + + // great lets pass the dictionary through the forkserver FD + u32 len = __afl_dictionary_len, offset = 0; + s32 ret; + + if (write(FORKSRV_FD + 1, &len, 4) != 4) { + + write(2, "Error: could not send dictionary len\n", + strlen("Error: could not send dictionary len\n")); + _exit(1); + + } + + while (len != 0) { + + ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); + + if (ret < 1) { + + write(2, "Error: could not send dictionary\n", + strlen("Error: could not send dictionary\n")); + _exit(1); + + } + + len -= ret; + offset += ret; + + } + + } else { + + // uh this forkserver master does not understand extended option passing + // or does not want the dictionary + already_read_first = 1; + + } + + } + while (1) { - u32 was_killed; int status; - /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (already_read_first) { - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + already_read_first = 0; + + } else { + + /* Wait for parent by reading from the pipe. Abort if read fails. */ + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + } /* If we stopped the child in persistent mode, but there was a race condition and afl-fuzz already issued SIGKILL, write off the old @@ -291,26 +359,92 @@ static void __afl_start_forkserver(void) { #endif - static u8 tmp[4]; - s32 child_pid; + u8 tmp[4] = {0, 0, 0, 0}; + s32 child_pid; + u32 status = 0; + u32 map_size = MAP_SIZE; + u32 already_read_first = 0; + u32 was_killed; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; u8 child_stopped = 0; void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); + if (map_size <= 0x1000000) + status |= (FS_OPT_SET_MAPSIZE(map_size) | FS_OPT_MAPSIZE); + if (__afl_dictionary_len > 0 && __afl_dictionary) status |= FS_OPT_AUTODICT; + if (status) status |= (FS_OPT_ENABLED); + memcpy(tmp, &status, 4); + /* Phone home and tell the parent that we're OK. If parent isn't there, assume we're not running in forkserver mode and just execute program. */ if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + if (__afl_dictionary_len > 0 && __afl_dictionary) { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == + (FS_OPT_ENABLED | FS_OPT_AUTODICT)) { + + // great lets pass the dictionary through the forkserver FD + u32 len = __afl_dictionary_len, offset = 0; + s32 ret; + + if (write(FORKSRV_FD + 1, &len, 4) != 4) { + + write(2, "Error: could not send dictionary len\n", + strlen("Error: could not send dictionary len\n")); + _exit(1); + + } + + while (len != 0) { + + ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); + + if (ret < 1) { + + write(2, "Error: could not send dictionary\n", + strlen("Error: could not send dictionary\n")); + _exit(1); + + } + + len -= ret; + offset += ret; + + } + + } else { + + // uh this forkserver master does not understand extended option passing + // or does not want the dictionary + already_read_first = 1; + + } + + } + while (1) { - u32 was_killed; int status; /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + if (already_read_first) { + + already_read_first = 0; + + } else { + + if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + + } /* If we stopped the child in persistent mode, but there was a race condition and afl-fuzz already issued SIGKILL, write off the old @@ -378,8 +512,12 @@ static void __afl_start_forkserver(void) { int __afl_persistent_loop(unsigned int max_cnt) { - static u8 first_pass = 1; - static u32 cycle_cnt; + static u8 first_pass = 1; + static u32 cycle_cnt; + unsigned int map_size = MAP_SIZE; + + if (__afl_final_loc > 1 && __afl_final_loc < MAP_SIZE) + map_size = __afl_final_loc; if (first_pass) { @@ -390,7 +528,7 @@ int __afl_persistent_loop(unsigned int max_cnt) { if (is_persistent) { - memset(__afl_area_ptr, 0, MAP_SIZE); + memset(__afl_area_ptr, 0, map_size); __afl_area_ptr[0] = 1; memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); diff --git a/qemu_mode/patches/afl-qemu-cpu-inl.h b/qemu_mode/patches/afl-qemu-cpu-inl.h index 3bd107d7..d73566fc 100644 --- a/qemu_mode/patches/afl-qemu-cpu-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-inl.h @@ -293,7 +293,7 @@ static void print_mappings(void) { void afl_forkserver(CPUState *cpu) { - static unsigned char tmp[4]; + static unsigned char tmp[4] = {0, 0, 0, 0}; if (forkserver_installed == 1) return; forkserver_installed = 1; diff --git a/src/afl-common.c b/src/afl-common.c index 825cd827..5216c7e0 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -59,6 +59,7 @@ char *afl_environment_variables[] = { "AFL_LD_HARD_FAIL", "AFL_LD_LIMIT_MB", "AFL_LD_NO_CALLOC_OVER", "AFL_LD_PRELOAD", "AFL_LD_VERBOSE", "AFL_LLVM_CMPLOG", "AFL_LLVM_INSTRIM", "AFL_LLVM_CTX", "AFL_LLVM_INSTRUMENT", "AFL_LLVM_INSTRIM_LOOPHEAD", + "AFL_LLVM_LTO_AUTODICTIONARY", "AFL_LLVM_AUTODICTIONARY", "AFL_LLVM_INSTRIM_SKIPSINGLEBLOCK", "AFL_LLVM_LAF_SPLIT_COMPARES", "AFL_LLVM_LAF_SPLIT_COMPARES_BITW", "AFL_LLVM_LAF_SPLIT_FLOATS", "AFL_LLVM_LAF_SPLIT_SWITCHES", "AFL_LLVM_LAF_TRANSFORM_COMPARES", diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 56c3c9d5..d1037194 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -69,7 +69,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { fsrv->mem_limit = MEM_LIMIT; fsrv->child_pid = -1; fsrv->out_dir_fd = -1; - + fsrv->map_size = MAP_SIZE; fsrv->use_fauxsrv = 0; fsrv->prev_timed_out = 0; @@ -82,7 +82,7 @@ void afl_fsrv_init(afl_forkserver_t *fsrv) { static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { - unsigned char tmp[4] = {0}; + unsigned char tmp[4] = {0, 0, 0, 0}; pid_t child_pid = -1; /* Phone home and tell the parent that we're OK. If parent isn't there, @@ -167,9 +167,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, int status; s32 rlen; - if (fsrv->use_fauxsrv) ACTF("Using Fauxserver:"); + if (!be_quiet) ACTF("Using Fauxserver:"); - if (!getenv("AFL_QUIET")) ACTF("Spinning up the fork server..."); + if (!be_quiet) ACTF("Spinning up the fork server..."); if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); @@ -340,7 +340,93 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (rlen == 4) { - if (!getenv("AFL_QUIET")) OKF("All right - fork server is up."); + if (!be_quiet) OKF("All right - fork server is up."); + + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + + if (!be_quiet) + ACTF("Extended forkserver functions received (%08x).", status); + + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + + fsrv->snapshot = 1; + if (!be_quiet) ACTF("Using SNAPSHOT feature."); + + } + + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + + fsrv->map_size = FS_OPT_GET_MAPSIZE(status); + if (fsrv->map_size % 8) + fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); + if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + + } + + if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + + // this is not afl-fuzz - we deny and return + status = (0xffffffff ^ (FS_OPT_ENABLED | FS_OPT_AUTODICT)); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + return; + + } + + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + + if (!be_quiet) ACTF("Using AUTODICT feature."); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) + FATAL("Writing to forkserver failed."); + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) + FATAL("Reading from forkserver failed."); + + if (status < 2 || (u32)status > 0xffffff) + FATAL("Dictionary has an illegal size: %d", status); + + u32 len = status, offset = 0, count = 0; + u8 *dict = ck_alloc(len); + if (dict == NULL) + FATAL("Could not allocate %u bytes of autodictionary memmory", len); + + while (len != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } + + } + + len = status; + offset = 0; + while (offset < status && (u8)dict[offset] + offset < status) { + + fsrv->function_ptr(fsrv->function_opt, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) ACTF("Loaded %u autodictionary entries", count); + ck_free(dict); + + } + + } + return; } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index c5347dcb..1c965532 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -78,16 +78,17 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { u64 *current = (u64 *)afl->fsrv.trace_bits; u64 *virgin = (u64 *)virgin_map; - u32 i = (MAP_SIZE >> 3); + u32 i = (afl->fsrv.map_size >> 3); #else u32 *current = (u32 *)afl->fsrv.trace_bits; u32 *virgin = (u32 *)virgin_map; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); #endif /* ^WORD_SIZE_64 */ + if (i == 0) i = 1; u8 ret = 0; @@ -148,12 +149,14 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { /* Count the number of bits set in the provided bitmap. Used for the status screen several times every second, does not have to be fast. */ -u32 count_bits(u8 *mem) { +u32 count_bits(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -182,12 +185,14 @@ u32 count_bits(u8 *mem) { mostly to update the status screen or calibrate and examine confirmed new paths. */ -u32 count_bytes(u8 *mem) { +u32 count_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -207,12 +212,14 @@ u32 count_bytes(u8 *mem) { /* Count the number of non-255 bytes set in the bitmap. Used strictly for the status screen, several calls per second or so. */ -u32 count_non_255_bytes(u8 *mem) { +u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) { u32 *ptr = (u32 *)mem; - u32 i = (MAP_SIZE >> 2); + u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; + if (i == 0) i = 1; + while (i--) { u32 v = *(ptr++); @@ -245,9 +252,11 @@ const u8 simplify_lookup[256] = { #ifdef WORD_SIZE_64 -void simplify_trace(u64 *mem) { +void simplify_trace(afl_state_t *afl, u64 *mem) { + + u32 i = (afl->fsrv.map_size >> 3); - u32 i = MAP_SIZE >> 3; + if (i == 0) i = 1; while (i--) { @@ -278,9 +287,11 @@ void simplify_trace(u64 *mem) { #else -void simplify_trace(u32 *mem) { +void simplify_trace(afl_state_t *afl, u32 *mem) { - u32 i = MAP_SIZE >> 2; + u32 i = (afl->fsrv.map_size >> 2); + + if (i == 0) i = 1; while (i--) { @@ -340,9 +351,11 @@ void init_count_class16(void) { #ifdef WORD_SIZE_64 -void classify_counts(u64 *mem) { +void classify_counts(afl_state_t *afl, u64 *mem) { + + u32 i = (afl->fsrv.map_size >> 3); - u32 i = MAP_SIZE >> 3; + if (i == 0) i = 1; while (i--) { @@ -367,9 +380,11 @@ void classify_counts(u64 *mem) { #else -void classify_counts(u32 *mem) { +void classify_counts(afl_state_t *afl, u32 *mem) { + + u32 i = (afl->fsrv.map_size >> 2); - u32 i = MAP_SIZE >> 2; + if (i == 0) i = 1; while (i--) { @@ -396,11 +411,11 @@ void classify_counts(u32 *mem) { count information here. This is called only sporadically, for some new paths. */ -void minimize_bits(u8 *dst, u8 *src) { +void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) { u32 i = 0; - while (i < MAP_SIZE) { + while (i < afl->fsrv.map_size) { if (*(src++)) dst[i >> 3] |= 1 << (i & 7); ++i; @@ -527,7 +542,7 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u8 fn[PATH_MAX]; /* Update path frequency. */ - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); struct queue_entry *q = afl->queue; while (q) { @@ -611,9 +626,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_tmout)) return keeping; @@ -675,9 +690,9 @@ u8 save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { if (likely(!afl->dumb_mode)) { #ifdef WORD_SIZE_64 - simplify_trace((u64 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u64 *)afl->fsrv.trace_bits); #else - simplify_trace((u32 *)afl->fsrv.trace_bits); + simplify_trace(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ if (!has_new_bits(afl, afl->virgin_crash)) return keeping; diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 5ad73539..ed4be6e4 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -389,7 +389,7 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); + memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); MEM_BARRIER(); /* Since we always have a forkserver (or a fauxserver) running, we can simply @@ -469,9 +469,9 @@ u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { tb4 = *(u32 *)afl->fsrv.trace_bits; #ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)afl->fsrv.trace_bits); #else - classify_counts((u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; diff --git a/src/afl-fuzz-extras.c b/src/afl-fuzz-extras.c index 16806934..55146dd9 100644 --- a/src/afl-fuzz-extras.c +++ b/src/afl-fuzz-extras.c @@ -305,10 +305,14 @@ static inline u8 memcmp_nocase(u8 *m1, u8 *m2, u32 len) { } /* Maybe add automatic extra. */ +/* Ugly hack: afl state is transfered as u8* because we import data via + afl-forkserver.c - which is shared with other afl tools that do not + have the afl state struct */ -void maybe_add_auto(afl_state_t *afl, u8 *mem, u32 len) { +void maybe_add_auto(void *afl_tmp, u8 *mem, u32 len) { - u32 i; + afl_state_t *afl = (afl_state_t *)afl_tmp; + u32 i; /* Allow users to specify that they don't want auto dictionaries. */ @@ -469,7 +473,7 @@ void load_auto(afl_state_t *afl) { if (len < 0) PFATAL("Unable to read from '%s'", fn); if (len >= MIN_AUTO_EXTRA && len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, tmp, len); + maybe_add_auto((u8 *)afl, tmp, len); close(fd); ck_free(fn); diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 6e0485e5..94ce9604 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -448,11 +448,13 @@ static void check_map_coverage(afl_state_t *afl) { u32 i; - if (count_bytes(afl->fsrv.trace_bits) < 100) return; + if (count_bytes(afl, afl->fsrv.trace_bits) < 100) return; for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i) if (afl->fsrv.trace_bits[i]) return; + if (afl->fsrv.map_size != MAP_SIZE) return; + WARNF("Recompile binary with newer version of afl to improve coverage!"); } diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index 754b2190..81504e29 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -244,7 +244,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (afl->stop_soon || fault == FAULT_ERROR) { goto abort_trimming; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (cksum == q->exec_cksum) { @@ -257,7 +257,8 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace_custom, afl->fsrv.trace_bits, + afl->fsrv.map_size); } @@ -307,7 +308,7 @@ u8 trim_case_custom(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace_custom, afl->fsrv.map_size); update_bitmap_score(afl, q); } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index b20bde90..80567160 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -601,7 +601,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -613,7 +613,7 @@ u8 fuzz_one_original(afl_state_t *afl) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -621,7 +621,7 @@ u8 fuzz_one_original(afl_state_t *afl) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -761,7 +761,7 @@ u8 fuzz_one_original(afl_state_t *afl) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; @@ -2615,7 +2615,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (!afl->dumb_mode && (afl->stage_cur & 7) == 7) { - u32 cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + u32 cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (afl->stage_cur == afl->stage_max - 1 && cksum == prev_cksum) { @@ -2627,7 +2627,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { ++a_len; if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); } else if (cksum != prev_cksum) { @@ -2635,7 +2635,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { worthwhile queued up, and collect that if the answer is yes. */ if (a_len >= MIN_AUTO_EXTRA && a_len <= MAX_AUTO_EXTRA) - maybe_add_auto(afl, a_collect, a_len); + maybe_add_auto((u8 *)afl, a_collect, a_len); a_len = 0; prev_cksum = cksum; @@ -2775,7 +2775,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { without wasting time on checksums. */ if (!afl->dumb_mode && len >= EFF_MIN_LEN) - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); else cksum = ~afl->queue_cur->exec_cksum; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index 174d7d92..346c2639 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -195,7 +195,7 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { /* For every byte set in afl->fsrv.trace_bits[], see if there is a previous winner, and how it compares to us. */ - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->fsrv.trace_bits[i]) { @@ -248,8 +248,10 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { if (!q->trace_mini) { - q->trace_mini = ck_alloc(MAP_SIZE >> 3); - minimize_bits(q->trace_mini, afl->fsrv.trace_bits); + u32 len = (afl->fsrv.map_size >> 3); + if (len == 0) len = 1; + q->trace_mini = ck_alloc(len); + minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); } @@ -268,14 +270,17 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { void cull_queue(afl_state_t *afl) { struct queue_entry *q; - u8 temp_v[MAP_SIZE >> 3]; + u32 len = (afl->fsrv.map_size >> 3); u32 i; + u8 temp_v[MAP_SIZE >> 3]; + + if (len == 0) len = 1; if (afl->dumb_mode || !afl->score_changed) return; afl->score_changed = 0; - memset(temp_v, 255, MAP_SIZE >> 3); + memset(temp_v, 255, len); afl->queued_favored = 0; afl->pending_favored = 0; @@ -292,10 +297,10 @@ void cull_queue(afl_state_t *afl) { /* Let's see if anything in the bitmap isn't captured in temp_v. If yes, and if it has a afl->top_rated[] contender, let's use it. */ - for (i = 0; i < MAP_SIZE; ++i) + for (i = 0; i < afl->fsrv.map_size; ++i) if (afl->top_rated[i] && (temp_v[i >> 3] & (1 << (i & 7)))) { - u32 j = MAP_SIZE >> 3; + u32 j = len; /* Remove all bits belonging to the current entry from temp_v. */ diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 4acc204b..517f8d7c 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -88,7 +88,7 @@ static u8 get_exec_checksum(afl_state_t *afl, u8 *buf, u32 len, u32 *cksum) { if (unlikely(common_fuzz_stuff(afl, buf, len))) return 1; - *cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + *cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); return 0; } @@ -332,7 +332,7 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { } - maybe_add_auto(afl, (u8 *)&v, shape); + maybe_add_auto((u8 *)afl, (u8 *)&v, shape); u64 rev; switch (shape) { @@ -340,15 +340,15 @@ static void try_to_add_to_dict(afl_state_t *afl, u64 v, u8 shape) { case 1: break; case 2: rev = SWAP16((u16)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 4: rev = SWAP32((u32)v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; case 8: rev = SWAP64(v); - maybe_add_auto(afl, (u8 *)&rev, shape); + maybe_add_auto((u8 *)afl, (u8 *)&rev, shape); break; } @@ -486,8 +486,8 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { // If failed, add to dictionary if (fails == 8) { - maybe_add_auto(afl, o->v0, SHAPE_BYTES(h->shape)); - maybe_add_auto(afl, o->v1, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape)); + maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape)); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 9bbdd23a..850a18bc 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -44,7 +44,7 @@ u8 run_target(afl_state_t *afl, u32 timeout) { must prevent any earlier operations from venturing into that territory. */ - memset(afl->fsrv.trace_bits, 0, MAP_SIZE); + memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); MEM_BARRIER(); @@ -122,9 +122,9 @@ u8 run_target(afl_state_t *afl, u32 timeout) { tb4 = *(u32 *)afl->fsrv.trace_bits; #ifdef WORD_SIZE_64 - classify_counts((u64 *)afl->fsrv.trace_bits); + classify_counts(afl, (u64 *)afl->fsrv.trace_bits); #else - classify_counts((u32 *)afl->fsrv.trace_bits); + classify_counts(afl, (u32 *)afl->fsrv.trace_bits); #endif /* ^WORD_SIZE_64 */ afl->fsrv.prev_timed_out = afl->fsrv.child_timed_out; @@ -315,7 +315,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, afl->shm.cmplog_mode) init_cmplog_forkserver(afl); - if (q->exec_cksum) memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE); + if (q->exec_cksum) + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); start_us = get_cur_time_us(); @@ -336,14 +337,14 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (afl->stop_soon || fault != afl->crash_mode) goto abort_calibration; if (!afl->dumb_mode && !afl->stage_cur && - !count_bytes(afl->fsrv.trace_bits)) { + !count_bytes(afl, afl->fsrv.trace_bits)) { fault = FAULT_NOINST; goto abort_calibration; } - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); if (q->exec_cksum != cksum) { @@ -354,7 +355,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, u32 i; - for (i = 0; i < MAP_SIZE; ++i) { + for (i = 0; i < afl->fsrv.map_size; ++i) { if (unlikely(!afl->var_bytes[i]) && unlikely(afl->first_trace[i] != afl->fsrv.trace_bits[i])) @@ -368,7 +369,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } else { q->exec_cksum = cksum; - memcpy(afl->first_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -385,7 +386,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, This is used for fuzzing air time calculations in calculate_score(). */ q->exec_us = (stop_us - start_us) / afl->stage_max; - q->bitmap_size = count_bytes(afl->fsrv.trace_bits); + q->bitmap_size = count_bytes(afl, afl->fsrv.trace_bits); q->handicap = handicap; q->cal_failed = 0; @@ -413,7 +414,7 @@ abort_calibration: if (var_detected) { - afl->var_byte_count = count_bytes(afl->var_bytes); + afl->var_byte_count = count_bytes(afl, afl->var_bytes); if (!q->var_behavior) { @@ -640,7 +641,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { /* Note that we don't keep track of crashes or hangs here; maybe TODO? */ - cksum = hash32(afl->fsrv.trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); /* If the deletion had no impact on the trace, make it permanent. This isn't perfect for variable-path inputs, but we're just making a @@ -663,7 +664,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { if (!needs_write) { needs_write = 1; - memcpy(afl->clean_trace, afl->fsrv.trace_bits, MAP_SIZE); + memcpy(afl->clean_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); } @@ -705,7 +706,7 @@ u8 trim_case(afl_state_t *afl, struct queue_entry *q, u8 *in_buf) { ck_write(fd, in_buf, q->len, q->fname); close(fd); - memcpy(afl->fsrv.trace_bits, afl->clean_trace, MAP_SIZE); + memcpy(afl->fsrv.trace_bits, afl->clean_trace, afl->fsrv.map_size); update_bitmap_score(afl, q); } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index a8c14c31..80039d6f 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,6 +99,10 @@ void afl_state_init(afl_state_t *afl) { afl->fsrv.use_stdin = 1; + afl->fsrv.map_size = MAP_SIZE; + afl->fsrv.function_opt = (u8 *)afl; + afl->fsrv.function_ptr = &maybe_add_auto; + afl->cal_cycles = CAL_CYCLES; afl->cal_cycles_long = CAL_CYCLES_LONG; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index ab84bf3f..58a37298 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -37,7 +37,7 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, u8 fn[PATH_MAX]; s32 fd; FILE * f; - uint32_t t_bytes = count_non_255_bytes(afl->virgin_bits); + uint32_t t_bytes = count_non_255_bytes(afl, afl->virgin_bits); snprintf(fn, PATH_MAX, "%s/fuzzer_stats", afl->out_dir); @@ -258,8 +258,8 @@ void show_stats(afl_state_t *afl) { /* Do some bitmap stats. */ - t_bytes = count_non_255_bytes(afl->virgin_bits); - t_byte_ratio = ((double)t_bytes * 100) / MAP_SIZE; + t_bytes = count_non_255_bytes(afl, afl->virgin_bits); + t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size; if (likely(t_bytes) && unlikely(afl->var_byte_count)) stab_ratio = 100 - (((double)afl->var_byte_count * 100) / t_bytes); @@ -305,7 +305,7 @@ void show_stats(afl_state_t *afl) { /* Compute some mildly useful bitmap stats. */ - t_bits = (MAP_SIZE << 3) - count_bits(afl->virgin_bits); + t_bits = (afl->fsrv.map_size << 3) - count_bits(afl, afl->virgin_bits); /* Now, for the visuals... */ @@ -465,7 +465,8 @@ void show_stats(afl_state_t *afl) { SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp); sprintf(tmp, "%0.02f%% / %0.02f%%", - ((double)afl->queue_cur->bitmap_size) * 100 / MAP_SIZE, t_byte_ratio); + ((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size, + t_byte_ratio); SAYF(" map density : %s%-21s" bSTG bV "\n", t_byte_ratio > 70 ? cLRD diff --git a/src/afl-tmin.c b/src/afl-tmin.c index f899a6b5..53e8705d 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -258,7 +258,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, fsrv->child_timed_out = 0; - memset(fsrv->trace_bits, 0, MAP_SIZE); + memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); write_to_testcase(fsrv, mem, len); @@ -393,7 +393,7 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, } - cksum = hash32(fsrv->trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(fsrv->trace_bits, fsrv->map_size, HASH_CONST); if (first_run) orig_cksum = cksum; -- cgit 1.4.1 From 32ba60185eba8a3ae8eeba0b5830d1bb43e38473 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 11 Apr 2020 08:02:54 +0200 Subject: more refactoring and update changelog --- docs/Changelog.md | 11 +- include/afl-fuzz.h | 7 +- include/cmplog.h | 1 - include/forkserver.h | 2 +- src/afl-analyze.c | 6 +- src/afl-forkserver.c | 1 + src/afl-fuzz-cmplog.c | 469 +----------------------------------------------- src/afl-fuzz-mutators.c | 6 +- src/afl-fuzz-run.c | 14 +- src/afl-fuzz-state.c | 7 + src/afl-fuzz.c | 10 +- src/afl-showmap.c | 3 +- src/afl-tmin.c | 3 +- 13 files changed, 50 insertions(+), 490 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0ec330a7..a1b55a69 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,7 +10,16 @@ sending a mail to . ### Version ++2.63d (development): - - LTO mode now requires llvm11 - but compiles all targets! :) + - llvm_mode LTO mode: + - now requires llvm11 - but compiles all targets! :) + - autodictionary feature added, enable with AFL_LLVM_LTO_AUTODICTIONARY + - variable map size usage + - afl-fuzz: + - variable map size support added (only LTO mode can use this) + - snapshot feature usage now visible in UI + - extended forkserver: map_size and more information is communicated to + afl-fuzz (and afl-fuzz acts accordingly) + - more refactoring - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 97c1f31c..1440b645 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -331,7 +331,8 @@ typedef struct afl_env_vars { u8 afl_skip_cpufreq, afl_exit_when_done, afl_no_affinity, afl_skip_bin_check, afl_dumb_forksrv, afl_import_first, afl_custom_mutator_only, afl_no_ui, afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, - afl_bench_until_crash, afl_debug_child_output, afl_autoresume; + afl_bench_until_crash, afl_debug_child_output, afl_autoresume, + afl_cal_fast; u8 *afl_tmpdir, *afl_post_library, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, @@ -558,7 +559,7 @@ typedef struct afl_state { /* CmpLog */ - char *cmplog_binary; + char * cmplog_binary; afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ /* Custom mutators */ @@ -921,7 +922,7 @@ void save_cmdline(afl_state_t *, u32, char **); /* CmpLog */ -u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); +u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len); /* RedQueen */ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, diff --git a/include/cmplog.h b/include/cmplog.h index 4731f779..74e6a3bb 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -79,6 +79,5 @@ struct cmp_map { void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv); - #endif diff --git a/include/forkserver.h b/include/forkserver.h index e1707429..444f92df 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -68,7 +68,7 @@ typedef struct afl_forkserver { u8 qemu_mode; /* if running in qemu mode or not */ - char *cmplog_binary; /* the name of the cmplog binary */ + char *cmplog_binary; /* the name of the cmplog binary */ /* Function to kick off the forkserver child */ void (*init_child_func)(struct afl_forkserver *fsrv, char **argv); diff --git a/src/afl-analyze.c b/src/afl-analyze.c index b0e8afcb..66dbefab 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -58,7 +58,7 @@ static s32 child_pid; /* PID of the tested program */ -static u8 *trace_bits; /* SHM with instrumentation bitmap */ +static u8 *trace_bits; /* SHM with instrumentation bitmap */ static u8 *in_file, /* Analyzer input test case */ *prog_in; /* Targeted program input file */ @@ -75,7 +75,7 @@ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ static s32 dev_null_fd = -1; /* FD to /dev/null */ -static u8 edges_only, /* Ignore hit counts? */ +static u8 edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = 1; /* Use stdin for program input? */ @@ -83,7 +83,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_timed_out; /* Child timed out? */ static u8 *target_path; -static u8 qemu_mode; +static u8 qemu_mode; /* Constants used for describing byte behavior. */ diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 3c0ad4a2..a7067791 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -187,6 +187,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, FATAL("Different forkserver not compatible with fauxserver"); fsrv->init_child_func = afl_fauxsrv_execv; + } if (pipe(st_pipe) || pipe(ctl_pipe)) PFATAL("pipe() failed"); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index 4d8bb58f..6f201013 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -30,6 +30,7 @@ #include "cmplog.h" typedef struct cmplog_data { + } cmplog_data_t; void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { @@ -38,479 +39,12 @@ void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->qemu_mode && argv[0] != fsrv->cmplog_binary) { -#if 0 - afl->fsrv.child_timed_out = 0; - afl->cmplog_fsrv_pid = fork(); - - if (afl->cmplog_fsrv_pid < 0) PFATAL("fork() failed"); - - if (!afl->cmplog_fsrv_pid) { - - /* CHILD PROCESS */ - - struct rlimit r; - - /* Umpf. On OpenBSD, the default fd limit for root users is set to - soft 128. Let's try to fix that... */ - - if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) { - - r.rlim_cur = FORKSRV_FD + 2; - setrlimit(RLIMIT_NOFILE, &r); /* Ignore errors */ - - } - - if (afl->fsrv.mem_limit) { - - r.rlim_max = r.rlim_cur = ((rlim_t)afl->fsrv.mem_limit) << 20; - -#ifdef RLIMIT_AS - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ -#else - /* This takes care of OpenBSD, which doesn't have RLIMIT_AS, but - according to reliable sources, RLIMIT_DATA covers anonymous - maps - so we should be getting good protection against OOM bugs. */ - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ -#endif /* ^RLIMIT_AS */ - - } - - /* Dumping cores is slow and can lead to anomalies if SIGKILL is delivered - before the dump is complete. */ - - // r.rlim_max = r.rlim_cur = 0; - // setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ - - /* Isolate the process and configure standard descriptors. If - afl->fsrv.out_file is specified, stdin is /dev/null; otherwise, - afl->fsrv.out_fd is cloned instead. */ - - setsid(); - - if (!(afl->afl_env.afl_debug_child_output)) { - - dup2(afl->fsrv.dev_null_fd, 1); - dup2(afl->fsrv.dev_null_fd, 2); - - } - - if (!afl->fsrv.use_stdin) { - - dup2(afl->fsrv.dev_null_fd, 0); - - } else { - - dup2(afl->fsrv.out_fd, 0); - close(afl->fsrv.out_fd); - - } - - /* Set up control and status pipes, close the unneeded original fds. */ - - if (dup2(ctl_pipe[0], FORKSRV_FD) < 0) PFATAL("dup2() failed"); - if (dup2(st_pipe[1], FORKSRV_FD + 1) < 0) PFATAL("dup2() failed"); - - close(ctl_pipe[0]); - close(ctl_pipe[1]); - close(st_pipe[0]); - close(st_pipe[1]); - - close(afl->fsrv.out_dir_fd); - close(afl->fsrv.dev_null_fd); -#ifndef HAVE_ARC4RANDOM - close(afl->fsrv.dev_urandom_fd); -#endif - if (afl->fsrv.plot_file != NULL) fclose(afl->fsrv.plot_file); - - /* This should improve performance a bit, since it stops the linker from - doing extra work post-fork(). */ - - if (!getenv("LD_BIND_LAZY")) setenv("LD_BIND_NOW", "1", 0); - - /* Set sane defaults for ASAN if nothing else specified. */ - - setenv("ASAN_OPTIONS", - "abort_on_error=1:" - "detect_leaks=0:" - "malloc_context_size=0:" - "symbolize=0:" - "allocator_may_return_null=1", - 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. */ - - 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", - 0); - - setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); - - if (!afl->qemu_mode && afl->argv[0] != afl->cmplog_binary) { - - ck_free(afl->argv[0]); - afl->argv[0] = afl->cmplog_binary; - - } - - execv(afl->argv[0], afl->argv); - - /* Use a distinctive bitmap signature to tell the parent about execv() - falling through. */ - - *(u32 *)afl->fsrv.trace_bits = EXEC_FAIL_SIG; - exit(0); - - } - - /* PARENT PROCESS */ - - /* Close the unneeded endpoints. */ - - close(ctl_pipe[0]); - close(st_pipe[1]); - - afl->cmplog_fsrv_ctl_fd = ctl_pipe[1]; - afl->cmplog_fsrv_st_fd = st_pipe[0]; - - /* Wait for the fork server to come up, but don't wait too long. */ - - rlen = 0; - if (afl->fsrv.exec_tmout) { - - rlen = 4; - u32 timeout_ms = afl->fsrv.exec_tmout * FORK_WAIT_MULT; - /* Reuse readfds as exceptfds to see when the child closed the pipe */ - u32 exec_ms = read_timed(afl->cmplog_fsrv_st_fd, &status, rlen, timeout_ms, - &afl->stop_soon); - - if (!exec_ms) { - - PFATAL("Error in timed read"); - - } else if (exec_ms > timeout_ms) { - - afl->fsrv.child_timed_out = 1; - kill(afl->cmplog_fsrv_pid, SIGKILL); - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - } else { - - rlen = read(afl->cmplog_fsrv_st_fd, &status, 4); - - } - - /* If we have a four-byte "hello" message from the server, we're all set. - Otherwise, try to figure out what went wrong. */ - - if (afl->fsrv.child_timed_out) - FATAL( - "Timeout while initializing cmplog fork server (adjusting -t may " - "help)"); - - if (rlen == 4) { - - OKF("All right - fork server is up."); - return; - - } - - if (waitpid(afl->cmplog_fsrv_pid, &status, 0) <= 0) - PFATAL("waitpid() failed"); - - if (WIFSIGNALED(status)) { - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && - afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! Since it seems to be built with ASAN and you " - "have a\n" - " restrictive memory limit configured, this is expected; please " - "read\n" - " %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF("\n" cLRD "[-] " cRST - "Whoops, the target binary crashed suddenly, " - "before receiving any input\n" - " from the fuzzer! There are several probable explanations:\n\n" - - " - The current memory limit (%s) is too restrictive, causing " - "the\n" - " target to hit an OOM condition in the dynamic linker. Try " - "bumping up\n" - " the limit with the -m setting in the command line. A simple " - "way confirm\n" - " this diagnosis would be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to " - "quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - The binary is just buggy and explodes entirely on its own. " - "If so, you\n" - " need to fix the underlying problem or find a better " - "replacement.\n\n" - - MSG_FORK_ON_APPLE - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - stringify_mem_size(val_buf, sizeof(val_buf), - afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server crashed with signal %d", WTERMSIG(status)); - - } - - if (*(u32 *)afl->fsrv.trace_bits == EXEC_FAIL_SIG) - FATAL("Unable to execute target application ('%s')", afl->argv[0]); - - if (afl->fsrv.mem_limit && afl->fsrv.mem_limit < 500 && afl->fsrv.uses_asan) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Since it seems to be built " - "with ASAN and\n" - " you have a restrictive memory limit configured, this is " - "expected; please\n" - " read %s/notes_for_asan.md for help.\n", - doc_path); - - } else if (!afl->fsrv.mem_limit) { - - SAYF("\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. Perhaps there is a horrible " - "bug in the\n" - " fuzzer. Poke for troubleshooting " - "tips.\n"); - - } else { - - u8 val_buf[STRINGIFY_VAL_SIZE_MAX]; - - SAYF( - "\n" cLRD "[-] " cRST - "Hmm, looks like the target binary terminated " - "before we could complete a\n" - " handshake with the injected code. There are %s probable " - "explanations:\n\n" - - "%s" - " - The current memory limit (%s) is too restrictive, causing an " - "OOM\n" - " fault in the dynamic linker. This can be fixed with the -m " - "option. A\n" - " simple way to confirm the diagnosis may be:\n\n" - - MSG_ULIMIT_USAGE - " /path/to/fuzzed_app )\n\n" - - " Tip: you can use http://jwilk.net/software/recidivm to quickly\n" - " estimate the required amount of virtual memory for the " - "binary.\n\n" - - " - Less likely, there is a horrible bug in the fuzzer. If other " - "options\n" - " fail, poke for troubleshooting " - "tips.\n", - getenv(DEFER_ENV_VAR) ? "three" : "two", - getenv(DEFER_ENV_VAR) - ? " - You are using deferred forkserver, but __AFL_INIT() is " - "never\n" - " reached before the program terminates.\n\n" - : "", - stringify_mem_size(val_buf, sizeof(val_buf), afl->fsrv.mem_limit << 20), - afl->fsrv.mem_limit - 1); - - } - - FATAL("Cmplog fork server handshake failed"); - -} - -u8 run_cmplog_target(afl_state_t *afl, u32 timeout) { - - int status = 0; - u32 exec_ms; - - u32 tb4; - s32 res; - - afl->fsrv.child_timed_out = 0; - - /* After this memset, afl->fsrv.trace_bits[] are effectively volatile, so we - must prevent any earlier operations from venturing into that - territory. */ - - memset(afl->fsrv.trace_bits, 0, afl->fsrv.map_size); - MEM_BARRIER(); - - /* Since we always have a forkserver (or a fauxserver) running, we can simply - tell them to have at it and read back the pid from it.*/ - - if ((res = write(afl->cmplog_fsrv_ctl_fd, &afl->cmplog_prev_timed_out, 4)) != - 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if ((res = read(afl->cmplog_fsrv_st_fd, &afl->cmplog_child_pid, 4)) != 4) { - - if (afl->stop_soon) return 0; - RPFATAL(res, - "Unable to request new process from cmplog fork server (OOM?)"); - - } - - if (afl->cmplog_child_pid <= 0) - FATAL("Cmplog fork server is misbehaving (OOM?)"); - - /* Configure timeout, as requested by user, then wait for child to terminate. - */ - exec_ms = - read_timed(afl->cmplog_fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); - - if (exec_ms > timeout) { - - /* If there was no response from forkserver after timeout seconds, - we kill the child. The forkserver should inform us afterwards */ - - kill(afl->cmplog_child_pid, SIGKILL); - afl->fsrv.child_timed_out = 1; - - /* After killing the child, the forkserver should tell us */ - if (!read(afl->cmplog_fsrv_st_fd, &status, 4)) exec_ms = 0; - - } - - if (!exec_ms) { // Something went wrong. - - if (afl->stop_soon) return 0; - SAYF("\n" cLRD "[-] " cRST - "Unable to communicate with fork server. Some possible reasons:\n\n" - " - You've run out of memory. Use -m to increase the the memory " - "limit\n" - " to something higher than %lld.\n" - " - The binary or one of the libraries it uses manages to create\n" - " threads before the forkserver initializes.\n" - " - The binary, at least in some circumstances, exits in a way " - "that\n" - " also kills the parent process - raise() could be the " - "culprit.\n\n" - "If all else fails you can disable the fork server via " - "AFL_NO_FORKSRV=1.\n", - afl->fsrv.mem_limit); - RPFATAL(res, "Unable to communicate with fork server"); - - } - - if (!WIFSTOPPED(status)) afl->cmplog_child_pid = 0; - - if (afl->slowest_exec_ms < exec_ms) afl->slowest_exec_ms = exec_ms; - - ++afl->total_execs; - - /* Any subsequent operations on afl->fsrv.trace_bits must not be moved by the - compiler below this point. Past this location, afl->fsrv.trace_bits[] - behave very normally and do not have to be treated as volatile. */ - - MEM_BARRIER(); - - tb4 = *(u32 *)afl->fsrv.trace_bits; - -#ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)afl->fsrv.trace_bits); -#else - classify_counts(afl, (u32 *)afl->fsrv.trace_bits); -#endif /* ^WORD_SIZE_64 */ - - afl->cmplog_prev_timed_out = afl->fsrv.child_timed_out; - - /* Report outcome to caller. */ - - if (WIFSIGNALED(status) && !afl->stop_soon) { - - afl->kill_signal = WTERMSIG(status); - - if (afl->fsrv.child_timed_out && afl->kill_signal == SIGKILL) - return FAULT_TMOUT; - - return FAULT_CRASH; - - } - - /* A somewhat nasty hack for MSAN, which doesn't support abort_on_error and - must use a special exit code. */ - - if (afl->fsrv.uses_asan && WEXITSTATUS(status) == MSAN_ERROR) { - - afl->kill_signal = 0; - return FAULT_CRASH; - - } - - if ((afl->dumb_mode == 1 || afl->no_forkserver) && tb4 == EXEC_FAIL_SIG) - return FAULT_ERROR; - - return FAULT_NONE; -#else ck_free(argv[0]); argv[0] = fsrv->cmplog_binary; } execv(argv[0], argv); -#endif } @@ -571,3 +105,4 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { return 0; } + diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index a7d7ae18..efb1c117 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -34,7 +34,7 @@ void load_custom_mutator_py(afl_state_t *, char *); void setup_custom_mutator(afl_state_t *afl) { /* Try mutator library first */ - u8 *fn = getenv("AFL_CUSTOM_MUTATOR_LIBRARY"); + u8 *fn = afl->afl_env.afl_custom_mutator_library; if (fn) { @@ -52,7 +52,7 @@ void setup_custom_mutator(afl_state_t *afl) { /* Try Python module */ #ifdef USE_PYTHON - u8 *module_name = getenv("AFL_PYTHON_MODULE"); + u8 *module_name = afl->afl_env.afl_python_module; if (module_name) { @@ -67,7 +67,7 @@ void setup_custom_mutator(afl_state_t *afl) { } #else - if (getenv("AFL_PYTHON_MODULE")) + if (afl->afl_env.afl_python_module) FATAL("Your AFL binary was built without Python support"); #endif diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 3a178e87..4c98d788 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -69,8 +69,7 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { if (fsrv->child_pid <= 0) FATAL("Fork server is misbehaving (OOM?)"); - exec_ms = - read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); + exec_ms = read_timed(fsrv->fsrv_st_fd, &status, 4, timeout, &afl->stop_soon); if (exec_ms > timeout) { @@ -312,10 +311,17 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, count its spin-up time toward binary calibration. */ if (!afl->fsrv.fsrv_pid) { - if (afl->shm.cmplog_mode && afl->fsrv.init_child_func != cmplog_exec_child) { + + if (afl->shm.cmplog_mode && + afl->fsrv.init_child_func != cmplog_exec_child) { + FATAL("BUG in afl-fuzz detected. Cmplog mode not set correctly."); + } - afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + + afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); + } if (q->exec_cksum) diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 80039d6f..f58345fb 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -284,6 +284,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_autoresume = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_CAL_FAST", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TMPDIR", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 44c48088..3341898c 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -248,6 +248,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_state_init(afl); afl_fsrv_init(&afl->fsrv); + if (get_afl_env("AFL_DEBUG")) afl->debug = 1; read_afl_environment(afl, envp); exit_1 = !!afl->afl_env.afl_bench_just_one; @@ -690,7 +691,7 @@ int main(int argc, char **argv_orig, char **envp) { OKF("MOpt Mutator from github.com/puppet-meteor/MOpt-AFL"); if (afl->sync_id && afl->force_deterministic && - getenv("AFL_CUSTOM_MUTATOR_ONLY")) + afl->afl_env.afl_custom_mutator_only) WARNF( "Using -M master with the AFL_CUSTOM_MUTATOR_ONLY mutator options will " "result in no deterministic mutations being done!"); @@ -865,7 +866,7 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) afl->not_on_tty = 0; - if (get_afl_env("AFL_CAL_FAST")) { + if (afl->afl_env.afl_cal_fast) { /* Use less calibration cycles, for slow applications */ afl->cal_cycles = 3; @@ -873,8 +874,6 @@ int main(int argc, char **argv_orig, char **envp) { } - if (get_afl_env("AFL_DEBUG")) afl->debug = 1; - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ @@ -1024,7 +1023,8 @@ int main(int argc, char **argv_orig, char **envp) { SAYF("Spawning cmplog forkserver"); memcpy(&afl->cmplog_fsrv, &afl->fsrv, sizeof(afl->fsrv)); afl->cmplog_fsrv.init_child_func = cmplog_exec_child; - afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, afl->afl_env.afl_debug_child_output); + afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon, + afl->afl_env.afl_debug_child_output); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index a8198f79..c84fa36c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -949,7 +949,8 @@ 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); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); while (done == 0 && (dir_ent = readdir(dir_in))) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 8ad33814..3be6b2c0 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -1131,7 +1131,8 @@ int main(int argc, char **argv_orig, char **envp) { read_initial_file(); - afl_fsrv_start(fsrv, use_argv, &stop_soon, get_afl_env("AFL_DEBUG_CHILD_OUTPUT")? 1 :0); + afl_fsrv_start(fsrv, use_argv, &stop_soon, + get_afl_env("AFL_DEBUG_CHILD_OUTPUT") ? 1 : 0); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", fsrv->mem_limit, fsrv->exec_tmout, edges_only ? ", edges only" : ""); -- cgit 1.4.1 From aaf8835cdb39b774ce9636e45a28f2445dfdcb24 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 12:18:06 +0200 Subject: updated changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index a1b55a69..108ebd08 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,8 @@ sending a mail to . - afl-fuzz: - variable map size support added (only LTO mode can use this) - snapshot feature usage now visible in UI + - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also + static global and local variable comparisons (cannot find all though) - extended forkserver: map_size and more information is communicated to afl-fuzz (and afl-fuzz acts accordingly) - more refactoring -- cgit 1.4.1 From dda096da03cae528dee9fd53e64896e93efe8f4a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 13 Apr 2020 12:12:27 +0200 Subject: allow -L -1 to enable mopt in parallel to classic mutation --- docs/Changelog.md | 2 ++ docs/README.MOpt.md | 3 +++ include/afl-fuzz.h | 10 +++++----- src/afl-forkserver.c | 10 +++++----- src/afl-fuzz-one.c | 14 +++++++------- src/afl-fuzz-run.c | 2 +- src/afl-fuzz.c | 50 +++++++++++++++++++++++++++++++++----------------- 7 files changed, 56 insertions(+), 35 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 108ebd08..2c8bff3d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,8 @@ sending a mail to . - afl-fuzz: - variable map size support added (only LTO mode can use this) - snapshot feature usage now visible in UI + - Now setting "-L -1" will enable MOpt in parallel to normal mutation. + Additionally this allows to run dictionaries, radamsa and cmplog. - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also static global and local variable comparisons (cannot find all though) - extended forkserver: map_size and more information is communicated to diff --git a/docs/README.MOpt.md b/docs/README.MOpt.md index 94e63959..3de6d670 100644 --- a/docs/README.MOpt.md +++ b/docs/README.MOpt.md @@ -36,6 +36,9 @@ enter the pacemaker fuzzing mode. Setting 0 will enter the pacemaker fuzzing mode at first, which is recommended in a short time-scale evaluation. +Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in +parallel. + Other important parameters can be found in afl-fuzz.c, for instance, 'swarm_num': the number of the PSO swarms used in the fuzzing process. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 1440b645..a7fdc5f0 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -354,14 +354,14 @@ typedef struct afl_state { /* MOpt: Lots of globals, but mostly for the status UI and other things where it really makes no sense to haul them around as function parameters. */ - u64 limit_time_puppet, orig_hit_cnt_puppet, last_limit_time_start, - tmp_pilot_time, total_pacemaker_time, total_puppet_find, temp_puppet_find, - most_time_key, most_time, most_execs_key, most_execs, old_hit_count, - force_ui_update; + u64 orig_hit_cnt_puppet, last_limit_time_start, tmp_pilot_time, + total_pacemaker_time, total_puppet_find, temp_puppet_find, most_time_key, + most_time, most_execs_key, most_execs, old_hit_count, force_ui_update; MOpt_globals_t mopt_globals_core, mopt_globals_pilot; - s32 SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, key_module; + s32 limit_time_puppet, SPLICE_CYCLES_puppet, limit_time_sig, key_puppet, + key_module; double w_init, w_end, w_now; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 28f664fa..b282a119 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -365,9 +365,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, kill(fsrv->fsrv_pid, SIGKILL); } else { - + rlen = 4; - + } } else { @@ -631,9 +631,9 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, static void afl_fsrv_kill(afl_forkserver_t *fsrv) { - if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL); - if (fsrv->fsrv_pid > 0) kill(fsrv->fsrv_pid, SIGKILL); - if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } + if (fsrv->child_pid > 0) kill(fsrv->child_pid, SIGKILL); + if (fsrv->fsrv_pid > 0) kill(fsrv->fsrv_pid, SIGKILL); + if (waitpid(fsrv->fsrv_pid, NULL, 0) <= 0) { WARNF("error waitpid\n"); } } diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 80567160..95d622f2 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -4377,7 +4377,7 @@ void pso_updating(afl_state_t *afl) { u8 fuzz_one(afl_state_t *afl) { - int key_val_lv = 0; + int key_val_lv_1 = 0, key_val_lv_2 = 0; #ifdef _AFL_DOCUMENT_MUTATIONS @@ -4397,22 +4397,22 @@ u8 fuzz_one(afl_state_t *afl) { #endif - if (afl->limit_time_sig == 0) { + // if limit_time_sig == -1 then both are run after each other - key_val_lv = fuzz_one_original(afl); + if (afl->limit_time_sig <= 0) { key_val_lv_1 = fuzz_one_original(afl); } - } else { + if (afl->limit_time_sig != 0) { if (afl->key_module == 0) - key_val_lv = pilot_fuzzing(afl); + key_val_lv_2 = pilot_fuzzing(afl); else if (afl->key_module == 1) - key_val_lv = core_fuzzing(afl); + key_val_lv_2 = core_fuzzing(afl); else if (afl->key_module == 2) pso_updating(afl); } - return key_val_lv; + return (key_val_lv_1 | key_val_lv_2); #undef BUF_PARAMS diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 1ddd7e1a..514ba9ef 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -49,7 +49,7 @@ u8 run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { memset(fsrv->trace_bits, 0, fsrv->map_size); MEM_BARRIER(); - + /* we have the fork server (or faux server) up and running, so simply tell it to have at it, and then read back PID. */ diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 136a9519..8620a402 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -109,12 +109,12 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { "Mutator settings:\n" " -R[R] - add Radamsa as mutator, add another -R to exclusivly " "run it\n" - " -L minutes - use MOpt(imize) mode and set the limit time for " + " -L minutes - use MOpt(imize) mode and set the time limit for " "entering the\n" - " pacemaker mode (minutes of no new paths, 0 = " - "immediately).\n" - " a recommended value is 10-60. see " - "docs/README.MOpt.md\n" + " pacemaker mode (minutes of no new paths). 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, just use -c 0.\n\n" @@ -553,20 +553,33 @@ int main(int argc, char **argv_orig, char **envp) { case 'L': { /* MOpt mode */ if (afl->limit_time_sig) FATAL("Multiple -L options not supported"); - afl->limit_time_sig = 1; afl->havoc_max_mult = HAVOC_MAX_MULT_MOPT; - if (sscanf(optarg, "%llu", &afl->limit_time_puppet) < 1 || - optarg[0] == '-') + if (sscanf(optarg, "%d", &afl->limit_time_puppet) < 1) FATAL("Bad syntax used for -L"); + if (afl->limit_time_puppet == -1) { + + afl->limit_time_sig = -1; + afl->limit_time_puppet = 0; + + } else if (afl->limit_time_puppet < 0) { + + FATAL("-L value must be between 0 and 2000000 or -1"); + + } else { + + afl->limit_time_sig = 1; + + } + u64 limit_time_puppet2 = afl->limit_time_puppet * 60 * 1000; if (limit_time_puppet2 < afl->limit_time_puppet) FATAL("limit_time overflow"); afl->limit_time_puppet = limit_time_puppet2; - SAYF("limit_time_puppet %llu\n", afl->limit_time_puppet); + SAYF("limit_time_puppet %d\n", afl->limit_time_puppet); afl->swarm_now = 0; if (afl->limit_time_puppet == 0) afl->key_puppet = 1; @@ -701,11 +714,14 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->use_radamsa) { - if (afl->limit_time_sig) + if (afl->limit_time_sig > 0) FATAL( - "MOpt and Radamsa are mutually exclusive. We accept pull requests " - "that integrates MOpt with the optional mutators " - "(custom/radamsa/redquenn/...)."); + "MOpt and Radamsa are mutually exclusive unless you specify -L -1. " + "We accept pull requests that integrates MOpt with the optional " + "mutators (custom/radamsa/redqueen/...)."); + + if (afl->limit_time_sig && afl->use_radamsa > 1) + FATAL("Radamsa in radamsa-only mode can not run together with -L"); OKF("Using Radamsa add-on"); @@ -984,11 +1000,11 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->cmplog_binary) { - if (afl->limit_time_sig) + if (afl->limit_time_sig > 0) FATAL( - "MOpt and CmpLog are mutually exclusive. We accept pull requests " - "that integrates MOpt with the optional mutators " - "(custom/radamsa/redquenn/...)."); + "MOpt and CmpLog are mutually exclusive unless you specify -L -1. We " + "accept pull requests that integrates MOpt with the optional " + "mutators (custom/radamsa/redqueen/...)."); if (afl->unicorn_mode) FATAL("CmpLog and Unicorn mode are not compatible at the moment, sorry"); -- cgit 1.4.1 From b63dd7a464ce654647b7710eb491ecf0e48c443f Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 14 Apr 2020 12:07:46 +0200 Subject: NO_PYTHON documented --- README.md | 3 ++- docs/Changelog.md | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/README.md b/README.md index 302a8acf..f14ccd36 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ $ sudo make install Note that "make distrib" also builds llvm_mode, qemu_mode, unicorn_mode and more. If you just want plain afl then do "make all", however compiling and using at least llvm_mode is highly recommended for much better results - -hence in this case +hence in this case ```shell $ make source-only @@ -178,6 +178,7 @@ These build options exist: * STATIC - compile AFL++ static * ASAN_BUILD - compiles with memory sanitizer for debug purposes * PROFILING - compile with profiling information (gprof) +* NO_PYTHON - disable python support * AFL_NO_X86 - if compiling on non-intel/amd platforms * LLVM_CONFIG - if your distro doesn't use the standard name for llvm-config (e.g. Debian) diff --git a/docs/Changelog.md b/docs/Changelog.md index 2c8bff3d..e1e558b7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,6 +26,7 @@ sending a mail to . - more refactoring - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) + - added NO_PYTHON flag to disable python support when building afl-fuzz ### Version ++2.63c (release): -- cgit 1.4.1 From c961925356bf3388066969b9975b424c4cdae890 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 07:10:42 +0200 Subject: fix plot_data output and code-format --- docs/Changelog.md | 5 ++++- src/afl-fuzz-init.c | 2 ++ src/afl-fuzz-python.c | 2 +- src/afl-fuzz-run.c | 2 +- src/afl-fuzz-stats.c | 31 ++++++++++++++++--------------- src/afl-showmap.c | 4 ++-- src/afl-tmin.c | 2 +- 7 files changed, 27 insertions(+), 21 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index e1e558b7..60d83508 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,14 +19,17 @@ sending a mail to . - snapshot feature usage now visible in UI - Now setting "-L -1" will enable MOpt in parallel to normal mutation. Additionally this allows to run dictionaries, radamsa and cmplog. + - fix for cmplog/redqueen mode if stdin was used + - fix for writing a better plot_data file + - qemu_mode: fix for persistent mode - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also static global and local variable comparisons (cannot find all though) - extended forkserver: map_size and more information is communicated to afl-fuzz (and afl-fuzz acts accordingly) - - more refactoring - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) - added NO_PYTHON flag to disable python support when building afl-fuzz + - more refactoring ### Version ++2.63c (release): diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 55f7ce53..7131ceed 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -1419,6 +1419,8 @@ void setup_dirs_fds(afl_state_t *afl) { "# unix_time, cycles_done, cur_path, paths_total, " "pending_total, pending_favs, map_size, unique_crashes, " "unique_hangs, max_depth, execs_per_sec\n"); + fflush(afl->fsrv.plot_file); + /* ignore errors */ } diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 33f01797..d4519c6d 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -42,7 +42,7 @@ it just fills in `&py_mutator->something_buf, &py_mutator->something_size`. */ &((py_mutator_t *)py_mutator)->name##_size static size_t fuzz_py(void *py_mutator, u8 *buf, size_t buf_size, u8 **out_buf, - u8 *add_buf, size_t add_buf_size, size_t max_size) { + u8 *add_buf, size_t add_buf_size, size_t max_size) { size_t mutated_size; PyObject *py_args, *py_value; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6ad6444a..30ba0e65 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -34,7 +34,7 @@ information. The called program will update afl->fsrv->trace_bits. */ fsrv_run_result_t fuzz_run_target(afl_state_t *afl, afl_forkserver_t *fsrv, - u32 timeout) { + u32 timeout) { fsrv_run_result_t res = afl_fsrv_run_target(fsrv, timeout, &afl->stop_soon); // TODO: Don't classify for faults? diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 7cc9b920..c507b7f7 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -145,14 +145,15 @@ void write_stats_file(afl_state_t *afl, double bitmap_cvg, double stability, void maybe_update_plot_file(afl_state_t *afl, double bitmap_cvg, double eps) { - if (afl->plot_prev_qp == afl->queued_paths && - afl->plot_prev_pf == afl->pending_favored && - afl->plot_prev_pnf == afl->pending_not_fuzzed && - afl->plot_prev_ce == afl->current_entry && - afl->plot_prev_qc == afl->queue_cycle && - afl->plot_prev_uc == afl->unique_crashes && - afl->plot_prev_uh == afl->unique_hangs && - afl->plot_prev_md == afl->max_depth) + if (unlikely(afl->plot_prev_qp == afl->queued_paths && + afl->plot_prev_pf == afl->pending_favored && + afl->plot_prev_pnf == afl->pending_not_fuzzed && + afl->plot_prev_ce == afl->current_entry && + afl->plot_prev_qc == afl->queue_cycle && + afl->plot_prev_uc == afl->unique_crashes && + afl->plot_prev_uh == afl->unique_hangs && + afl->plot_prev_md == afl->max_depth) || + unlikely(!afl->queue_cycle)) return; afl->plot_prev_qp = afl->queued_paths; @@ -388,9 +389,9 @@ void show_stats(afl_state_t *afl) { /* Lord, forgive me this. */ - SAYF(SET_G1 bSTG bLT bH bSTOP cCYA + SAYF(SET_G1 bSTG bLT bH bSTOP cCYA " process timing " bSTG bH30 bH5 bH bHB bH bSTOP cCYA - " overall results " bSTG bH2 bH2 bRT "\n"); + " overall results " bSTG bH2 bH2 bRT "\n"); if (afl->dumb_mode) { @@ -472,9 +473,9 @@ void show_stats(afl_state_t *afl) { " uniq hangs : " cRST "%-6s" bSTG bV "\n", time_tmp, tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " cycle progress " bSTG bH10 bH5 bH2 bH2 bHB bH bSTOP cCYA - " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); + " map coverage " bSTG bH bHT bH20 bH2 bVL "\n"); /* This gets funny because we want to print several variable-length variables together, but then cram them into a fixed-width field - so we need to @@ -504,9 +505,9 @@ void show_stats(afl_state_t *afl) { SAYF(bSTOP " count coverage : " cRST "%-21s" bSTG bV "\n", tmp); - SAYF(bVR bH bSTOP cCYA + SAYF(bVR bH bSTOP cCYA " stage progress " bSTG bH10 bH5 bH2 bH2 bX bH bSTOP cCYA - " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); + " findings in depth " bSTG bH10 bH5 bH2 bH2 bVL "\n"); sprintf(tmp, "%s (%0.02f%%)", u_stringify_int(IB(0), afl->queued_favored), ((double)afl->queued_favored) * 100 / afl->queued_paths); @@ -580,7 +581,7 @@ void show_stats(afl_state_t *afl) { /* Aaaalmost there... hold on! */ - SAYF(bVR bH cCYA bSTOP + SAYF(bVR bH cCYA bSTOP " fuzzing strategy yields " bSTG bH10 bHT bH10 bH5 bHB bH bSTOP cCYA " path geometry " bSTG bH5 bH2 bVL "\n"); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 61c1754f..f43beb1b 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -218,8 +218,8 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { /* Execute target application. */ -static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, - u32 len) { +static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, char **argv, + u8 *mem, u32 len) { afl_fsrv_write_to_testcase(fsrv, mem, len); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 431ff0c4..0a462e9a 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -215,7 +215,7 @@ static s32 write_to_file(u8 *path, u8 *mem, u32 len) { 1 if they should be kept. */ static u8 tmin_run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, - u8 first_run) { + u8 first_run) { afl_fsrv_write_to_testcase(fsrv, mem, len); -- cgit 1.4.1 From 5b70d23211ddeddfb4d1dfce29a50234d08e9502 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 09:10:49 +0200 Subject: added AFL_MAP_SIZE (wip) --- docs/Changelog.md | 1 + include/afl-fuzz.h | 2 ++ include/config.h | 3 +-- include/forkserver.h | 2 +- src/afl-analyze.c | 22 ++++++++++++++++------ src/afl-common.c | 2 +- src/afl-forkserver.c | 21 +++++++++++++-------- src/afl-fuzz-bitmap.c | 16 +--------------- src/afl-fuzz-init.c | 19 ------------------- src/afl-fuzz-queue.c | 9 +++++---- src/afl-fuzz-state.c | 24 +++++++++++++++++++++++- src/afl-fuzz.c | 12 +++++++----- src/afl-gcc.c | 8 ++++++++ src/afl-showmap.c | 24 ++++++++++++++++++------ src/afl-tmin.c | 27 +++++++++++++++++++-------- 15 files changed, 116 insertions(+), 76 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 60d83508..3ad80b7b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,6 +26,7 @@ sending a mail to . static global and local variable comparisons (cannot find all though) - extended forkserver: map_size and more information is communicated to afl-fuzz (and afl-fuzz acts accordingly) + - new environment variable: AFL_MAP_SIZE to specify the size of the shared map - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) - added NO_PYTHON flag to disable python support when building afl-fuzz diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 363776cb..88cacc4f 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -325,6 +325,8 @@ typedef struct afl_env_vars { *afl_python_module, *afl_path, *afl_hang_tmout, *afl_skip_crashes, *afl_preload; + uint32_t map_size; + } afl_env_vars_t; struct afl_pass_stat { diff --git a/include/config.h b/include/config.h index f0274fd3..fae97a42 100644 --- a/include/config.h +++ b/include/config.h @@ -407,8 +407,7 @@ #define FS_OPT_SNAPSHOT 0x20000000 #define FS_OPT_AUTODICT 0x10000000 #define FS_OPT_GET_MAPSIZE(x) (((x & 0x00fffffe) >> 1) + 1) -#define FS_OPT_SET_MAPSIZE(x) \ - (x <= 1 || x > MAP_SIZE || x > 0x1000000 ? 0 : ((x - 1) << 1)) +#define FS_OPT_SET_MAPSIZE(x) (x <= 1 || x > 0x1000000 ? 0 : ((x - 1) << 1)) #endif /* ! _HAVE_CONFIG_H */ diff --git a/include/forkserver.h b/include/forkserver.h index ac89b681..d76dfc7a 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -61,7 +61,7 @@ typedef struct afl_forkserver { u64 total_execs; /* How often run_target was called */ u8 *out_file, /* File to fuzz, if any */ - *target_path; /* Path of the target */ + *target_path; /* Path of the target */ FILE *plot_file; /* Gnuplot output file */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 6f946ed5..3d86efb1 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -84,6 +84,7 @@ static volatile u8 stop_soon, /* Ctrl-C pressed? */ static u8 *target_path; static u8 qemu_mode; +static u32 map_size = MAP_SIZE; /* Constants used for describing byte behavior. */ @@ -115,7 +116,7 @@ static u8 count_class_lookup[256] = { static void classify_counts(u8 *mem) { - u32 i = MAP_SIZE; + u32 i = map_size; if (edges_only) { @@ -144,7 +145,7 @@ static void classify_counts(u8 *mem) { static inline u8 anything_set(void) { u32 *ptr = (u32 *)trace_bits; - u32 i = (MAP_SIZE >> 2); + u32 i = (map_size >> 2); while (i--) if (*(ptr++)) return 1; @@ -217,7 +218,7 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { s32 prog_in_fd; u32 cksum; - memset(trace_bits, 0, MAP_SIZE); + memset(trace_bits, 0, map_size); MEM_BARRIER(); prog_in_fd = write_to_file(prog_in, mem, len); @@ -311,7 +312,7 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { } - cksum = hash32(trace_bits, MAP_SIZE, HASH_CONST); + cksum = hash32(trace_bits, map_size, HASH_CONST); /* We don't actually care if the target is crashing or not, except that when it does, the checksum should be different. */ @@ -811,7 +812,7 @@ int main(int argc, char **argv, char **envp) { s32 opt; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; - char **use_argv; + char **use_argv, *ptr; doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; @@ -931,12 +932,21 @@ int main(int argc, char **argv, char **envp) { if (optind == argc || !in_file) usage(argv[0]); + if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { + + map_size = atoi(ptr); + if (map_size < 8 || map_size > (1 << 29)) + FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size); + if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3); + + } + use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX"); check_environment_vars(envp); sharedmem_t shm = {0}; - trace_bits = afl_shm_init(&shm, MAP_SIZE, 0); + trace_bits = afl_shm_init(&shm, map_size, 0); atexit(at_exit_handler); setup_signal_handlers(); diff --git a/src/afl-common.c b/src/afl-common.c index c9f09d38..3210ee97 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -72,7 +72,7 @@ char *afl_environment_variables[] = { "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", "AFL_NO_BUILTIN", "AFL_NO_CPU_RED", "AFL_NO_FORKSRV", "AFL_NO_UI", "AFL_NO_X86", // not really an env but we dont want to warn on it - "AFL_PATH", "AFL_PERFORMANCE_FILE", + "AFL_MAP_SIZE", "AFL_MAPSIZE", "AFL_PATH", "AFL_PERFORMANCE_FILE", //"AFL_PERSISTENT", // not implemented anymore, so warn additionally "AFL_POST_LIBRARY", "AFL_PRELOAD", "AFL_PYTHON_MODULE", "AFL_QEMU_COMPCOV", "AFL_QEMU_COMPCOV_DEBUG", "AFL_QEMU_DEBUG_MAPS", "AFL_QEMU_DISABLE_CACHE", diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 006764d9..9b915a7a 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -407,21 +407,26 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { - fsrv->map_size = FS_OPT_GET_MAPSIZE(status); - if (unlikely(fsrv->map_size % 8)) { + u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); + + if (!fsrv->map_size) fsrv->map_size = MAP_SIZE; + + if (unlikely(tmp_map_size % 8)) { // should not happen - WARNF("Target reported non-aligned map size of %ud", fsrv->map_size); - fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); + WARNF("Target reported non-aligned map size of %ud", tmp_map_size); + tmp_map_size = (((tmp_map_size + 8) >> 3) << 3); } - if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); - if (fsrv->map_size > MAP_SIZE) + if (!be_quiet) ACTF("Target map size: %u", tmp_map_size); + if (tmp_map_size > fsrv->map_size) FATAL( "Target's coverage map size of %u is larger than the one this " - "afl++ is compiled with (%u) (change MAP_SIZE and recompile)\n", - fsrv->map_size, MAP_SIZE); + "afl++ is set with (%u) (change MAP_SIZE_POW2 in config.h and " + "recompile or set AFL_MAP_SIZE)\n", + tmp_map_size, fsrv->map_size); + fsrv->map_size = tmp_map_size; } diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index be8f504e..0823deed 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -43,7 +43,7 @@ void write_bitmap(afl_state_t *afl) { if (fd < 0) PFATAL("Unable to open '%s'", fname); - ck_write(fd, afl->virgin_bits, MAP_SIZE, fname); + ck_write(fd, afl->virgin_bits, afl->fsrv.map_size, fname); close(fd); @@ -145,8 +145,6 @@ u32 count_bits(afl_state_t *afl, u8 *mem) { u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; - if (i == 0) i = 1; - while (i--) { u32 v = *(ptr++); @@ -181,8 +179,6 @@ u32 count_bytes(afl_state_t *afl, u8 *mem) { u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; - if (i == 0) i = 1; - while (i--) { u32 v = *(ptr++); @@ -208,8 +204,6 @@ u32 count_non_255_bytes(afl_state_t *afl, u8 *mem) { u32 i = (afl->fsrv.map_size >> 2); u32 ret = 0; - if (i == 0) i = 1; - while (i--) { u32 v = *(ptr++); @@ -246,8 +240,6 @@ void simplify_trace(afl_state_t *afl, u64 *mem) { u32 i = (afl->fsrv.map_size >> 3); - if (i == 0) i = 1; - while (i--) { /* Optimize for sparse bitmaps. */ @@ -281,8 +273,6 @@ void simplify_trace(afl_state_t *afl, u32 *mem) { u32 i = (afl->fsrv.map_size >> 2); - if (i == 0) i = 1; - while (i--) { /* Optimize for sparse bitmaps. */ @@ -347,8 +337,6 @@ void classify_counts(afl_forkserver_t *fsrv) { u32 i = (fsrv->map_size >> 3); - if (i == 0) i = 1; - while (i--) { /* Optimize for sparse bitmaps. */ @@ -378,8 +366,6 @@ void classify_counts(afl_forkserver_t *fsrv) { u32 i = (fsrv->map_size >> 2); - if (i == 0) i = 1; - while (i--) { /* Optimize for sparse bitmaps. */ diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 7131ceed..3da348d2 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -442,23 +442,6 @@ void read_testcases(afl_state_t *afl) { } -/* Examine map coverage. Called once, for first test case. */ - -static void check_map_coverage(afl_state_t *afl) { - - u32 i; - - if (count_bytes(afl, afl->fsrv.trace_bits) < 100) return; - - for (i = (1 << (MAP_SIZE_POW2 - 1)); i < MAP_SIZE; ++i) - if (afl->fsrv.trace_bits[i]) return; - - if (afl->fsrv.map_size != MAP_SIZE) return; - - WARNF("Recompile binary with newer version of afl to improve coverage!"); - -} - /* Perform dry run of all test cases to confirm that the app is working as expected. This is done only for the initial inputs, and only once. */ @@ -501,8 +484,6 @@ void perform_dry_run(afl_state_t *afl) { case FSRV_RUN_OK: - if (q == afl->queue) check_map_coverage(afl); - if (afl->crash_mode) FATAL("Test case '%s' does *NOT* crash", fn); break; diff --git a/src/afl-fuzz-queue.c b/src/afl-fuzz-queue.c index d05eee08..373f12d8 100644 --- a/src/afl-fuzz-queue.c +++ b/src/afl-fuzz-queue.c @@ -249,7 +249,6 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) { if (!q->trace_mini) { u32 len = (afl->fsrv.map_size >> 3); - if (len == 0) len = 1; q->trace_mini = ck_alloc(len); minimize_bits(afl, q->trace_mini, afl->fsrv.trace_bits); @@ -272,12 +271,12 @@ void cull_queue(afl_state_t *afl) { struct queue_entry *q; u32 len = (afl->fsrv.map_size >> 3); u32 i; - u8 temp_v[MAP_SIZE >> 3]; - - if (len == 0) len = 1; + u8 * temp_v; if (afl->dumb_mode || !afl->score_changed) return; + temp_v = ck_alloc(afl->fsrv.map_size >> 3); + afl->score_changed = 0; memset(temp_v, 255, len); @@ -325,6 +324,8 @@ void cull_queue(afl_state_t *afl) { } + ck_free(temp_v); + } /* Calculate case desirability score to adjust the length of havoc fuzzing. diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 7664c521..7d068258 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -99,7 +99,11 @@ void afl_state_init(afl_state_t *afl) { afl->fsrv.use_stdin = 1; - afl->fsrv.map_size = MAP_SIZE; + if (afl->afl_env.map_size > 8 && afl->afl_env.map_size <= (1 << 29)) + afl->fsrv.map_size = afl->afl_env.map_size; + else + afl->fsrv.map_size = MAP_SIZE; + afl->fsrv.function_opt = (u8 *)afl; afl->fsrv.function_ptr = &maybe_add_auto; @@ -324,6 +328,24 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_path = (u8 *)get_afl_env(afl_environment_variables[i]); + } else if (!strncmp(env, "AFL_MAP_SIZE", + + afl_environment_variable_len) || + !strncmp(env, "AFL_MAPSIZE", + afl_environment_variable_len)) { + + afl->afl_env.map_size = + atoi((u8 *)get_afl_env(afl_environment_variables[i])); + + if (afl->afl_env.map_size < 8 || afl->afl_env.map_size > (1 << 29)) + FATAL( + "the specified AFL_MAP_SIZE size is illegal and must be " + "between 2^3 and 2^30: %u\n", + afl->afl_env.map_size); + + if (afl->afl_env.map_size % 8) + afl->afl_env.map_size = (((afl->afl_env.map_size >> 3) + 1) << 3); + } else if (!strncmp(env, "AFL_PRELOAD", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 925dbb1a..3cf57f86 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -249,6 +249,7 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_DEBUG")) afl->debug = 1; read_afl_environment(afl, envp); + if (afl->afl_env.map_size) afl->fsrv.map_size = afl->afl_env.map_size; exit_1 = !!afl->afl_env.afl_bench_just_one; SAYF(cCYA "afl-fuzz" VERSION cRST @@ -476,7 +477,7 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->in_bitmap) FATAL("Multiple -B options not supported"); afl->in_bitmap = optarg; - read_bitmap(afl->in_bitmap, afl->virgin_bits, MAP_SIZE); + read_bitmap(afl->in_bitmap, afl->virgin_bits, afl->fsrv.map_size); break; case 'C': /* crash mode */ @@ -910,13 +911,14 @@ int main(int argc, char **argv_orig, char **envp) { check_crash_handling(); check_cpu_governor(afl); - afl->fsrv.trace_bits = afl_shm_init(&afl->shm, MAP_SIZE, afl->dumb_mode); + afl->fsrv.trace_bits = + afl_shm_init(&afl->shm, afl->fsrv.map_size, afl->dumb_mode); setup_post(afl); - if (!afl->in_bitmap) memset(afl->virgin_bits, 255, MAP_SIZE); - memset(afl->virgin_tmout, 255, MAP_SIZE); - memset(afl->virgin_crash, 255, MAP_SIZE); + if (!afl->in_bitmap) memset(afl->virgin_bits, 255, afl->fsrv.map_size); + memset(afl->virgin_tmout, 255, afl->fsrv.map_size); + memset(afl->virgin_crash, 255, afl->fsrv.map_size); init_count_class16(); diff --git a/src/afl-gcc.c b/src/afl-gcc.c index 32cd36cb..86a88014 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -411,6 +411,14 @@ int main(int argc, char **argv) { } + u8 *ptr; + if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { + + u32 map_size = atoi(ptr); + if (map_size != MAP_SIZE) FATAL("AFL_MAP_SIZE is not supported by afl-gcc"); + + } + find_as(argv[0]); edit_params(argc, argv); diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 21e18061..c1561b4c 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -72,6 +72,8 @@ static u32 total, highest; /* tuple content information */ static u32 in_len, /* Input data length */ arg_offset; /* Total number of execs */ +static u32 map_size = MAP_SIZE; + static u8 quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ @@ -112,7 +114,7 @@ static void classify_counts(afl_forkserver_t *fsrv) { u8 * mem = fsrv->trace_bits; const u8 *map = binary_mode ? count_class_binary : count_class_human; - u32 i = MAP_SIZE; + u32 i = map_size; if (edges_only) { @@ -175,10 +177,10 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (binary_mode) { - for (i = 0; i < MAP_SIZE; i++) + for (i = 0; i < map_size; i++) if (fsrv->trace_bits[i]) ret++; - ck_write(fd, fsrv->trace_bits, MAP_SIZE, outfile); + ck_write(fd, fsrv->trace_bits, map_size, outfile); close(fd); } else { @@ -187,7 +189,7 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { if (!f) PFATAL("fdopen() failed"); - for (i = 0; i < MAP_SIZE; i++) { + for (i = 0; i < map_size; i++) { if (!fsrv->trace_bits[i]) continue; ret++; @@ -535,7 +537,7 @@ 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 **use_argv, *ptr; char **argv = argv_cpy_dup(argc, argv_orig); @@ -543,6 +545,16 @@ int main(int argc, char **argv_orig, char **envp) { afl_forkserver_t *fsrv = &fsrv_var; afl_fsrv_init(fsrv); + if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { + + map_size = atoi(ptr); + if (map_size < 8 || map_size > (1 << 29)) + FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size); + if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3); + fsrv->map_size = map_size; + + } + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; if (getenv("AFL_QUIET") != NULL) be_quiet = 1; @@ -715,7 +727,7 @@ int main(int argc, char **argv_orig, char **envp) { check_environment_vars(envp); sharedmem_t shm = {0}; - fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0); + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); setup_signal_handlers(); set_up_environment(fsrv); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 0a462e9a..e366d260 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -70,7 +70,8 @@ static u32 in_len, /* Input data length */ orig_cksum, /* Original checksum */ missed_hangs, /* Misses due to hangs */ missed_crashes, /* Misses due to crashes */ - missed_paths; /* Misses due to exec path diffs */ + missed_paths, /* Misses due to exec path diffs */ + map_size = MAP_SIZE; static u8 crash_mode, /* Crash-centric mode? */ hang_mode, /* Minimize as long as it hangs */ @@ -105,7 +106,7 @@ static const u8 count_class_lookup[256] = { static void apply_mask(u32 *mem, u32 *mask) { - u32 i = (MAP_SIZE >> 2); + u32 i = (map_size >> 2); if (!mask) return; @@ -122,7 +123,7 @@ static void apply_mask(u32 *mem, u32 *mask) { static void classify_counts(afl_forkserver_t *fsrv) { u8 *mem = fsrv->trace_bits; - u32 i = MAP_SIZE; + u32 i = map_size; if (edges_only) { @@ -151,7 +152,7 @@ static void classify_counts(afl_forkserver_t *fsrv) { static inline u8 anything_set(afl_forkserver_t *fsrv) { u32 *ptr = (u32 *)fsrv->trace_bits; - u32 i = (MAP_SIZE >> 2); + u32 i = (map_size >> 2); while (i--) if (*(ptr++)) return 1; @@ -755,7 +756,7 @@ int main(int argc, char **argv_orig, char **envp) { s32 opt; u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; - char **use_argv; + char **use_argv, *ptr; char **argv = argv_cpy_dup(argc, argv_orig); @@ -763,6 +764,16 @@ int main(int argc, char **argv_orig, char **envp) { afl_forkserver_t *fsrv = &fsrv_var; afl_fsrv_init(fsrv); + if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { + + map_size = atoi(ptr); + if (map_size < 8 || map_size > (1 << 29)) + FATAL("illegal AFL_MAP_SIZE %u, must be between 2^3 and 2^30", map_size); + if (map_size % 8) map_size = (((map_size >> 3) + 1) << 3); + fsrv->map_size = map_size; + + } + doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n"); @@ -910,8 +921,8 @@ int main(int argc, char **argv_orig, char **envp) { to be useful. */ if (mask_bitmap) FATAL("Multiple -B options not supported"); - mask_bitmap = ck_alloc(MAP_SIZE); - read_bitmap(optarg, mask_bitmap, MAP_SIZE); + mask_bitmap = ck_alloc(map_size); + read_bitmap(optarg, mask_bitmap, map_size); break; case 'h': @@ -928,7 +939,7 @@ int main(int argc, char **argv_orig, char **envp) { check_environment_vars(envp); sharedmem_t shm = {0}; - fsrv->trace_bits = afl_shm_init(&shm, MAP_SIZE, 0); + fsrv->trace_bits = afl_shm_init(&shm, map_size, 0); atexit(at_exit_handler); setup_signal_handlers(); -- cgit 1.4.1 From ef311ec70cd9f58cc58fe67fd693d94e01edbf98 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 10:08:56 +0200 Subject: done implementing AFL_MAP_SIZE --- docs/env_variables.md | 5 +++++ gcc_plugin/afl-gcc-fast.c | 10 ++++++++++ llvm_mode/afl-clang-fast.c | 10 ++++++++++ llvm_mode/afl-llvm-lto-instrumentation.so.cc | 28 +++++++++++++++------------- src/afl-gcc.c | 3 ++- 5 files changed, 42 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/env_variables.md b/docs/env_variables.md index 7890da35..21bf9fad 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -243,6 +243,11 @@ checks or alter some of the more exotic semantics of the tool: normally indicated by the cycle counter in the UI turning green. May be convenient for some types of automated jobs. + - AFL_MAP_SIZE sets the size of the shared map that afl-fuzz, afl-showmap, + afl-tmin and afl-analyze create to gather instrumentation data from + the target. This must be equal or larger than the size the target was + compiled with. + - Setting AFL_NO_AFFINITY disables attempts to bind to a specific CPU core on Linux systems. This slows things down, but lets you run more instances of afl-fuzz than would be prudent (if you really want to). diff --git a/gcc_plugin/afl-gcc-fast.c b/gcc_plugin/afl-gcc-fast.c index 8953c523..0e51ee62 100644 --- a/gcc_plugin/afl-gcc-fast.c +++ b/gcc_plugin/afl-gcc-fast.c @@ -364,6 +364,16 @@ int main(int argc, char **argv, char **envp) { be_quiet = 1; + u8 *ptr; + if (!be_quiet && + ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) { + + u32 map_size = atoi(ptr); + if (map_size != MAP_SIZE) + FATAL("AFL_MAP_SIZE is not supported by afl-gcc-fast"); + + } + check_environment_vars(envp); find_obj(argv[0]); diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index c0471033..5abe61c6 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -796,6 +796,16 @@ int main(int argc, char **argv, char **envp) { } + u8 *ptr2; + if (!be_quiet && instrument_mode != INSTRUMENT_LTO && + ((ptr2 = getenv("AFL_MAP_SIZE")) || (ptr2 = getenv("AFL_MAPSIZE")))) { + + u32 map_size = atoi(ptr2); + if (map_size != MAP_SIZE) + FATAL("AFL_MAP_SIZE is not supported by afl-clang-fast"); + + } + if (debug) { SAYF(cMGN "[D]" cRST " cd \"%s\";", getthecwd()); diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index c5e7a2b7..a5058974 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -608,20 +608,22 @@ bool AFLLTOPass::runOnModule(Module &M) { } - // save highest location ID to global variable - // do this after each function to fail faster - if (afl_global_id > MAP_SIZE) { - - uint32_t pow2map = 1, map = afl_global_id; - while ((map = map >> 1)) - pow2map++; - FATAL( - "We have %u blocks to instrument but the map size is only %u! Edit " - "config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " - "afl-fuzz and llvm_mode.", - afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map); + } - } + // save highest location ID to global variable + // do this after each function to fail faster + if (!be_quiet && afl_global_id > MAP_SIZE) { + + uint32_t pow2map = 1, map = afl_global_id; + while ((map = map >> 1)) + pow2map++; + WARNF( + "We have %u blocks to instrument but the map size is only %u. Either " + "edit config.h and set MAP_SIZE_POW2 from %u to %u, then recompile " + "afl-fuzz and llvm_mode and then make this target - or set " + "AFL_MAP_SIZE with at least size %u when running afl-fuzz with this " + "target.", + afl_global_id, MAP_SIZE, MAP_SIZE_POW2, pow2map, afl_global_id); } diff --git a/src/afl-gcc.c b/src/afl-gcc.c index 86a88014..1ae10975 100644 --- a/src/afl-gcc.c +++ b/src/afl-gcc.c @@ -412,7 +412,8 @@ int main(int argc, char **argv) { } u8 *ptr; - if ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE"))) { + if (!be_quiet && + ((ptr = getenv("AFL_MAP_SIZE")) || (ptr = getenv("AFL_MAPSIZE")))) { u32 map_size = atoi(ptr); if (map_size != MAP_SIZE) FATAL("AFL_MAP_SIZE is not supported by afl-gcc"); -- cgit 1.4.1 From f70d4a6fd4a14d81658c2726748949bbf25ec1fb Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 17 Apr 2020 11:07:03 +0200 Subject: added bugfix infos --- docs/Changelog.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3ad80b7b..9c563f7c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,13 +12,13 @@ sending a mail to . ### Version ++2.63d (development): - llvm_mode LTO mode: - now requires llvm11 - but compiles all targets! :) - - autodictionary feature added, enable with AFL_LLVM_LTO_AUTODICTIONARY + - autodictionary feature added, enable with `AFL_LLVM_LTO_AUTODICTIONARY` - variable map size usage - afl-fuzz: - variable map size support added (only LTO mode can use this) - snapshot feature usage now visible in UI - - Now setting "-L -1" will enable MOpt in parallel to normal mutation. - Additionally this allows to run dictionaries, radamsa and cmplog. + - Now setting `-L -1` will enable MOpt in parallel to normal mutation. + Additionally, this allows to run dictionaries, radamsa and cmplog. - fix for cmplog/redqueen mode if stdin was used - fix for writing a better plot_data file - qemu_mode: fix for persistent mode @@ -30,6 +30,8 @@ sending a mail to . - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) - added NO_PYTHON flag to disable python support when building afl-fuzz + - Bugfix: in persistent mode, fuzzing could get stuck after initial crash (#319) + - Bugfix: alf-plot output (#320) - more refactoring @@ -318,7 +320,7 @@ sending a mail to . you use the new -p option :-) - see docs/power_schedules.md - added afl-system-config script to set all system performance options for fuzzing - llvm_mode works with llvm 3.9 up to including 8 ! - - qemu_mode got upgraded from 2.1 to 3.1 - incorporated from + - qemu_mode got upgraded from 2.1 to 3.1 - incorporated from https://github.com/andreafioraldi/afl and with community patches added -- cgit 1.4.1 From c9605f22514181caf7823e382a94c2bcf59e5a95 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 14:10:18 +0200 Subject: ++2.64c --- docs/Changelog.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'docs') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9c563f7c..9d6b5f87 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++2.63d (development): +### Version ++2.64c (release): - llvm_mode LTO mode: - now requires llvm11 - but compiles all targets! :) - autodictionary feature added, enable with `AFL_LLVM_LTO_AUTODICTIONARY` @@ -21,7 +21,7 @@ sending a mail to . Additionally, this allows to run dictionaries, radamsa and cmplog. - fix for cmplog/redqueen mode if stdin was used - fix for writing a better plot_data file - - qemu_mode: fix for persistent mode + - qemu_mode: fix for persistent mode (which would not terminate or get stuck) - compare-transform/AFL_LLVM_LAF_TRANSFORM_COMPARES now transforms also static global and local variable comparisons (cannot find all though) - extended forkserver: map_size and more information is communicated to @@ -30,8 +30,6 @@ sending a mail to . - if AFL_CC/AFL_CXX is set but empty afl compilers did fail, fixed (this bug is in vanilla afl too) - added NO_PYTHON flag to disable python support when building afl-fuzz - - Bugfix: in persistent mode, fuzzing could get stuck after initial crash (#319) - - Bugfix: alf-plot output (#320) - more refactoring -- cgit 1.4.1