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 --- 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 +- 5 files changed, 59 insertions(+), 1003 deletions(-) delete mode 100644 llvm_mode/afl-ld.c (limited to 'llvm_mode') 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 'llvm_mode') 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 b8d84ababb22e2b2be3f38036e6f7e3aae5d050f Mon Sep 17 00:00:00 2001 From: van Hauser Date: Thu, 9 Apr 2020 13:13:07 +0200 Subject: lto module clean-up (#303) --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 87 +++------------------------- 1 file changed, 7 insertions(+), 80 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 2a9b17b2..93968984 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -23,12 +23,6 @@ */ -// CONFIG OPTION: -// If #define USE_SPLIT is used, then the llvm::SplitEdge function is used -// instead of our own implementation. Ours looks better and will -// compile everywhere. But it is not working for complex code. yet. damn. -#define USE_SPLIT - #define AFL_LLVM_PASS #include "config.h" @@ -44,31 +38,17 @@ #include #include "llvm/Config/llvm-config.h" -#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5 -typedef long double max_align_t; -#endif - #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Module.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" - -#ifdef USE_SPLIT #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#endif - -#if LLVM_VERSION_MAJOR > 3 || \ - (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) #include "llvm/IR/DebugInfo.h" #include "llvm/IR/CFG.h" -#else -#include "llvm/DebugInfo.h" -#include "llvm/Support/CFG.h" -#endif using namespace llvm; @@ -91,7 +71,6 @@ class AFLLTOPass : public ModulePass { } -#ifdef USE_SPLIT void getAnalysisUsage(AnalysisUsage &AU) const override { ModulePass::getAnalysisUsage(AU); @@ -100,8 +79,6 @@ class AFLLTOPass : public ModulePass { } -#endif - // Calculate the number of average collisions that would occur if all // location IDs would be assigned randomly (like normal afl/afl++). // This uses the "balls in bins" algorithm. @@ -179,20 +156,14 @@ bool AFLLTOPass::runOnModule(Module &M) { LLVMContext &C = M.getContext(); - IntegerType * Int8Ty = IntegerType::getInt8Ty(C); - IntegerType * Int32Ty = IntegerType::getInt32Ty(C); - struct timeval tv; - struct timezone tz; - u32 rand_seed; + IntegerType *Int8Ty = IntegerType::getInt8Ty(C); + IntegerType *Int32Ty = IntegerType::getInt32Ty(C); - /* Setup random() so we get Actually Random(TM) outputs from AFL_R() */ - gettimeofday(&tv, &tz); - rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid(); - AFL_SR(rand_seed); + if (getenv("AFL_DEBUG")) debug = 1; /* Show a banner */ - if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) { + if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { SAYF(cCYA "afl-llvm-lto" VERSION cRST " by Marc \"vanHauser\" Heuse \n"); @@ -201,10 +172,6 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; -#if LLVM_VERSION_MAJOR < 9 - char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); -#endif - /* Get globals for the SHM region and the previous location. Note that __afl_prev_loc is thread-local. */ @@ -224,12 +191,6 @@ bool AFLLTOPass::runOnModule(Module &M) { if (F.size() < 2) continue; if (isBlacklisted(&F)) continue; -#ifdef USE_SPLIT - // DominatorTree &DT = - // getAnalysis(F).getDomTree(); LoopInfo & LI = - // getAnalysis(F).getLoopInfo(); -#endif - std::vector InsBlocks; for (auto &BB : F) { @@ -274,11 +235,7 @@ bool AFLLTOPass::runOnModule(Module &M) { for (uint32_t j = 0; j < Successors.size(); j++) { -#ifdef USE_SPLIT BasicBlock *newBB = llvm::SplitEdge(origBB, Successors[j]); -#else - BasicBlock *newBB = BasicBlock::Create(C, "", &F, nullptr); -#endif if (!newBB) { @@ -287,12 +244,8 @@ bool AFLLTOPass::runOnModule(Module &M) { } -#ifdef USE_SPLIT BasicBlock::iterator IP = newBB->getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); -#else - IRBuilder<> IRB(&(*newBB)); -#endif /* Set the ID of the inserted basic block */ @@ -313,38 +266,12 @@ bool AFLLTOPass::runOnModule(Module &M) { Value *Incr = IRB.CreateAdd(Counter, One); -#if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in - // llvm is then fixed -#endif - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); -#if LLVM_VERSION_MAJOR < 9 - - } - -#endif + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); -#ifdef USE_SPLIT - // nothing -#else - - // Unconditional jump to the destination BB - - IRB.CreateBr(Successors[j]); - - // Replace the original destination to this newly inserted BB - - origBB->replacePhiUsesWith(Successors[j], newBB); - BasicBlock *S = Successors[j]; - S->replacePhiUsesWith(origBB, newBB); - TI->setSuccessor(j, newBB); - -#endif // done :) inst_blocks++; -- 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 'llvm_mode') 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 39e8b918062ee92be03480075fedefcb7801f32a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Fri, 10 Apr 2020 22:54:31 +0200 Subject: code format --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 5 +++-- src/afl-fuzz.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index f387e79c..28f6bf9e 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -517,8 +517,9 @@ bool AFLLTOPass::runOnModule(Module &M) { 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); + 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)); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9de80c72..836393ac 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -923,7 +923,8 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->file_extension) { - snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, afl->file_extension); + snprintf(tmpfile, PATH_MAX, "%s/.cur_input.%s", afl->tmp_dir, + afl->file_extension); } else { -- cgit 1.4.1 From 68f269437d0f502a5a091a6ed62cf8d71d0148d6 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 11 Apr 2020 07:32:42 +0200 Subject: Autodictionary (#309) * 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 * better map transfer, display snapshot in UI * update readme --- include/forkserver.h | 1 - llvm_mode/README.lto.md | 3 +- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 45 ++- llvm_mode/afl-llvm-rt.o.c | 4 +- src/afl-forkserver.c | 23 +- src/afl-fuzz-cmplog.c | 468 ++++++++++++++++++++++++++- src/afl-fuzz-stats.c | 26 +- 7 files changed, 528 insertions(+), 42 deletions(-) (limited to 'llvm_mode') diff --git a/include/forkserver.h b/include/forkserver.h index 24fa3e1b..e1707429 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -77,7 +77,6 @@ typedef struct afl_forkserver { 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/README.lto.md b/llvm_mode/README.lto.md index 48d0e36c..9fc444df 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -50,7 +50,8 @@ Example build output from a libtiff build: 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.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). +AUTODICTIONARY: 11 strings found +[+] Instrumented 12071 locations with no collisions (on average 1046 collisions would be in afl-gcc/afl-clang-fast) (non-hardened mode). ``` ## Building llvm 11 diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 28f6bf9e..5cdf0b70 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -468,15 +468,13 @@ bool AFLLTOPass::runOnModule(Module &M) { TmpConstStr.append("\0", 1); ConstStr = StringRef(TmpConstStr); - if (isSizedcmp && constLen > sizedLen) { constLen = sizedLen; } + if (isSizedcmp && constLen > sizedLen) constLen = sizedLen; - /* - if (!be_quiet) - errs() << callInst->getCalledFunction()->getName() << ": len " - << constLen << ": " << ConstStr << "\n"; - */ + if (debug) + errs() << callInst->getCalledFunction()->getName() << ": len " + << constLen << ": " << ConstStr << "\n"; - if (constLen && constLen < MAX_DICT_FILE) + if (constLen >= MIN_AUTO_EXTRA && constLen <= MAX_DICT_FILE) dictionary.push_back(ConstStr.str().substr(0, constLen)); } @@ -514,14 +512,22 @@ bool AFLLTOPass::runOnModule(Module &M) { 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)); + uint32_t write_loc = afl_global_id; + + if (afl_global_id % 8) write_loc = (((afl_global_id + 8) >> 3) << 3); + + if (write_loc <= MAP_SIZE && write_loc <= 0x800000) { + + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, + "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, + false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, write_loc); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } } @@ -537,7 +543,9 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (!be_quiet) printf("AUTODICTIONARY: %lu strings found\n", count); + if (!be_quiet) + printf("AUTODICTIONARY: %lu string%s found\n", count, + count == 1 ? "" : "s"); if (count) { @@ -549,13 +557,16 @@ bool AFLLTOPass::runOnModule(Module &M) { } + count = 0; + for (auto token : dictionary) { - if (offset + token.length() < 0xfffff0) { + if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) { ptr[offset++] = (uint8_t)token.length(); memcpy(ptr + offset, token.c_str(), token.length()); offset += token.length(); + count++; } diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index cbc4648d..3ad9eab4 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -208,7 +208,7 @@ static void __afl_start_snapshots(void) { assume we're not running in forkserver mode and just execute program. */ status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT); - if (map_size <= 0x1000000) + if (map_size <= 0x800000) 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); @@ -373,7 +373,7 @@ static void __afl_start_forkserver(void) { void (*old_sigchld_handler)(int) = 0; // = signal(SIGCHLD, SIG_DFL); - if (map_size <= 0x1000000) + if (map_size <= 0x800000) 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); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 7ab8a4b5..3c0ad4a2 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -367,23 +367,28 @@ 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 (fsrv->map_size % 8) + if (fsrv->map_size % 8) // should not happen fsrv->map_size = (((fsrv->map_size + 8) >> 3) << 3); if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); + if (fsrv->map_size > MAP_SIZE) + FATAL( + "Target's coverage map size of %u is larger than the one this " + "afl++ is compiled with (%u)\n", + fsrv->map_size, MAP_SIZE); } - if (fsrv->function_ptr == NULL || fsrv->function_opt == NULL) { + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - // 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 (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); diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index f9480dc4..4d8bb58f 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -38,12 +38,479 @@ 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 } @@ -104,4 +571,3 @@ u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len) { return 0; } - diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d83a747f..65876f67 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -366,9 +366,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) { @@ -450,9 +450,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 @@ -482,9 +482,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); @@ -558,7 +558,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"); @@ -737,6 +737,8 @@ void show_stats(afl_state_t *afl) { if (afl->cpu_core_count) { + char *spacing = SP10, snap[24] = " " cLGN "snapshot" cRST " "; + double cur_runnable = get_runnable_processes(); u32 cur_utilization = cur_runnable * 100 / afl->cpu_core_count; @@ -751,23 +753,25 @@ void show_stats(afl_state_t *afl) { if (!afl->no_cpu_meter_red && cur_utilization >= 150) cpu_color = cLRD; + if (afl->fsrv.snapshot) spacing = snap; + #ifdef HAVE_AFFINITY if (afl->cpu_aff >= 0) { - SAYF(SP10 cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, MIN(afl->cpu_aff, 999), - cpu_color, MIN(cur_utilization, 999)); + SAYF("%s" cGRA "[cpu%03u:%s%3u%%" cGRA "]\r" cRST, spacing, + MIN(afl->cpu_aff, 999), cpu_color, MIN(cur_utilization, 999)); } else { - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); } #else - SAYF(SP10 cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, cpu_color, + SAYF("%s" cGRA " [cpu:%s%3u%%" cGRA "]\r" cRST, spacing, cpu_color, MIN(cur_utilization, 999)); #endif /* ^HAVE_AFFINITY */ -- cgit 1.4.1 From 8bcfba8231aecc11a3815c74b6c53c86f418ece1 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 11 Apr 2020 07:35:54 +0200 Subject: add missing file --- llvm_mode/afl-llvm-rt-lto.o.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 llvm_mode/afl-llvm-rt-lto.o.c (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-rt-lto.o.c b/llvm_mode/afl-llvm-rt-lto.o.c new file mode 100644 index 00000000..5921f968 --- /dev/null +++ b/llvm_mode/afl-llvm-rt-lto.o.c @@ -0,0 +1,23 @@ +/* + american fuzzy lop++ - LLVM instrumentation bootstrap + ----------------------------------------------------- + + 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 + +*/ + +// to prevent the function from being removed +unsigned char __afl_lto_mode = 0; + +/* Proper initialization routine. */ + +__attribute__((constructor(0))) void __afl_auto_init_globals(void) { + + __afl_lto_mode = 1; + +} + -- cgit 1.4.1 From 90a9f22c3dca0f4ee51f3c37be5d95a082d43161 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sat, 11 Apr 2020 18:31:46 +0200 Subject: fix #312 --- llvm_mode/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index b176a24f..2bbc92c8 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -147,7 +147,7 @@ endif endif CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2 -override CFLAGS = -Wall \ +override CFLAGS += -Wall \ -g -Wno-pointer-sign -I ../include/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \ -- cgit 1.4.1 From eec725a345b2e1cf396fd96970333677f701e42e Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 10:34:03 +0200 Subject: add global and local var support to autodictionary --- llvm_mode/README.lto.md | 2 +- llvm_mode/afl-clang-fast.c | 4 +- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 330 +++++++++++++++++++-------- test/test-compcov.c | 10 + 4 files changed, 251 insertions(+), 95 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 9fc444df..51b50544 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -57,7 +57,7 @@ AUTODICTIONARY: 11 strings found ## Building llvm 11 ``` -$ sudo apt install binutils-dev +$ sudo apt install binutils-dev # this is *essential*! $ git clone https://github.com/llvm/llvm-project $ cd llvm-project $ mkdir build diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index cdb22cb9..fa76a11e 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -401,7 +401,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (getenv("AFL_NO_BUILTIN")) { + if (getenv("AFL_NO_BUILTIN") || (instrument_mode == INSTRUMENT_LTO && + (getenv("AFL_LLVM_LTO_AUTODICTIONARY") || + getenv("AFL_LLVM_AUTODICTIONARY")))) { cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 5cdf0b70..c5e7a2b7 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -161,9 +161,10 @@ class AFLLTOPass : public ModulePass { bool AFLLTOPass::runOnModule(Module &M) { - LLVMContext & C = M.getContext(); - std::vector dictionary; - std::vector calls; + LLVMContext & C = M.getContext(); + std::vector dictionary; + std::vector calls; + DenseMap valueMap; IntegerType *Int8Ty = IntegerType::getInt8Ty(C); IntegerType *Int32Ty = IntegerType::getInt32Ty(C); @@ -208,6 +209,34 @@ bool AFLLTOPass::runOnModule(Module &M) { if (autodictionary) { + /* Some implementation notes. + * + * We try to handle 3 cases: + * - memcmp("foo", arg, 3) <- literal string + * - static char globalvar[] = "foo"; + * memcmp(globalvar, arg, 3) <- global variable + * - char localvar[] = "foo"; + * memcmp(locallvar, arg, 3) <- local variable + * + * The local variable case is the hardest. We can only detect that + * case if there is no reassignment or change in the variable. + * And it might not work across llvm version. + * What we do is hooking the initializer function for local variables + * (llvm.memcpy.p0i8.p0i8.i64) and note the string and the assigned + * variable. And if that variable is then used in a compare function + * we use that noted string. + * This seems not to work for tokens that have a size <= 4 :-( + * + * - if the compared length is smaller than the string length we + * save the full string. This is likely better for fuzzing but + * might be wrong in a few cases depending on optimizers + * + * - not using StringRef because there is a bug in the llvm 11 + * checkout I am using which sometimes points to wrong strings + * + * Over and out. Took me a full day. damn. mh/vh + */ + for (auto &BB : F) { for (auto &IN : BB) { @@ -216,24 +245,28 @@ bool AFLLTOPass::runOnModule(Module &M) { if ((callInst = dyn_cast(&IN))) { - bool isStrcmp = true; - bool isMemcmp = true; - bool isStrncmp = true; - bool isStrcasecmp = true; - bool isStrncasecmp = true; + bool isStrcmp = true; + bool isMemcmp = true; + bool isStrncmp = true; + bool isStrcasecmp = true; + bool isStrncasecmp = true; + bool isIntMemcpy = true; + bool addedNull = false; + uint8_t optLen = 0; 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")); + std::string FuncName = Callee->getName().str(); + isStrcmp &= !FuncName.compare("strcmp"); + isMemcmp &= !FuncName.compare("memcmp"); + isStrncmp &= !FuncName.compare("strncmp"); + isStrcasecmp &= !FuncName.compare("strcasecmp"); + isStrncasecmp &= !FuncName.compare("strncasecmp"); + isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64"); if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && - !isStrncasecmp) + !isStrncasecmp && !isIntMemcpy) continue; /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function @@ -269,7 +302,7 @@ bool AFLLTOPass::runOnModule(Module &M) { FT->getParamType(2)->isIntegerTy(); if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && - !isStrncasecmp) + !isStrncasecmp && !isIntMemcpy) continue; /* is a str{n,}{case,}cmp/memcmp, check if we have @@ -278,29 +311,205 @@ bool AFLLTOPass::runOnModule(Module &M) { * 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); + std::string Str1, Str2; + StringRef TmpStr; + bool HasStr1 = getConstantStringInfo(Str1P, TmpStr); + if (TmpStr.empty()) + HasStr1 = false; + else + Str1 = TmpStr.str(); + bool HasStr2 = getConstantStringInfo(Str2P, TmpStr); + if (TmpStr.empty()) + HasStr2 = false; + else + Str2 = TmpStr.str(); + + if (debug) + fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n", + FuncName.c_str(), Str1P, Str1P->getName().str().c_str(), + Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P, + Str2P->getName().str().c_str(), Str2.c_str(), + HasStr2 == true ? "true" : "false"); + + // we handle the 2nd parameter first because of llvm memcpy + if (!HasStr2) { + + auto *Ptr = dyn_cast(Str2P); + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast(Ptr->getOperand(0))) { + + if (auto *Array = + dyn_cast(Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString().str(); + + } + + } + + } + + } + + // for the internal memcpy routine we only care for the second + // parameter and are not reporting anything. + if (isIntMemcpy == true) { + + if (HasStr2 == true) { + + Value * op2 = callInst->getArgOperand(2); + ConstantInt *ilen = dyn_cast(op2); + if (ilen) { + + uint64_t literalLength = Str2.size(); + uint64_t optLength = ilen->getZExtValue(); + if (literalLength + 1 == optLength) { + + Str2.append("\0", 1); // add null byte + addedNull = true; + + } + + } + + valueMap[Str1P] = new std::string(Str2); + + if (debug) + fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P); + continue; + + } + + continue; + + } + + // Neither a literal nor a global variable? + // maybe it is a local variable that we saved + if (!HasStr2) { + + std::string *strng = valueMap[Str2P]; + if (strng && !strng->empty()) { + + Str2 = *strng; + HasStr2 = true; + if (debug) + fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(), + Str2P); + + } + + } + + if (!HasStr1) { + + auto Ptr = dyn_cast(Str1P); + + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast(Ptr->getOperand(0))) { + + if (auto *Array = + dyn_cast(Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString().str(); + + } + + } + + } + + } + + // Neither a literal nor a global variable? + // maybe it is a local variable that we saved + if (!HasStr1) { + + std::string *strng = valueMap[Str1P]; + if (strng && !strng->empty()) { + + Str1 = *strng; + HasStr1 = true; + if (debug) + fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(), + Str1P); + + } + + } /* handle cases of one string is const, one string is variable */ if (!(HasStr1 ^ HasStr2)) continue; + std::string thestring; + + if (HasStr1) + thestring = Str1; + else + thestring = Str2; + + optLen = thestring.length(); + 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; + if (ilen) { + + uint64_t literalLength = optLen; + optLen = ilen->getZExtValue(); + if (literalLength + 1 == optLen) { // add null byte + thestring.append("\0", 1); + addedNull = true; + + } + + } } - calls.push_back(callInst); + // add null byte if this is a string compare function and a null + // was not already added + if (addedNull == false && !isMemcmp) { + + thestring.append("\0", 1); // add null byte + optLen++; + + } + + if (!be_quiet) { + + std::string outstring; + fprintf(stderr, "%s: length %u/%u \"", FuncName.c_str(), optLen, + (unsigned int)thestring.length()); + for (uint8_t i = 0; i < thestring.length(); i++) { + + uint8_t c = thestring[i]; + if (c <= 32 || c >= 127) + fprintf(stderr, "\\x%02x", c); + else + fprintf(stderr, "%c", c); + + } + + fprintf(stderr, "\"\n"); + + } + + // we take the longer string, even if the compare was to a + // shorter part. Note that depending on the optimizer of the + // compiler this can be wrong, but it is more likely that this + // is helping the fuzzer + if (optLen != thestring.length()) optLen = thestring.length(); + if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA; + if (optLen < MIN_AUTO_EXTRA) // too short? skip + continue; + + dictionary.push_back(thestring.substr(0, optLen)); } @@ -416,71 +625,6 @@ bool AFLLTOPass::runOnModule(Module &M) { } - if (calls.size()) { - - for (auto &callInst : calls) { - - 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 (debug) - errs() << callInst->getCalledFunction()->getName() << ": len " - << constLen << ": " << ConstStr << "\n"; - - if (constLen >= MIN_AUTO_EXTRA && constLen <= MAX_DICT_FILE) - dictionary.push_back(ConstStr.str().substr(0, constLen)); - - } - - } - if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL || dictionary.size()) { // yes we could create our own function, insert it into ctors ... diff --git a/test/test-compcov.c b/test/test-compcov.c index 89611bfb..fff9c759 100644 --- a/test/test-compcov.c +++ b/test/test-compcov.c @@ -3,8 +3,12 @@ #include #include +char global_cmpval[] = "GLOBALVARIABLE"; + int main(int argc, char **argv) { char *input = argv[1], *buf, buffer[20]; + char cmpval[] = "LOCALVARIABLE"; + char shortval[4] = "abc"; if (argc < 2) { ssize_t ret = read(0, buffer, sizeof(buffer) - 1); @@ -24,6 +28,12 @@ int main(int argc, char **argv) { return 0; } else if (*(unsigned int*)input == 0xabadcafe) printf("GG you eat cmp tokens for breakfast!\n"); + else if (memcmp(cmpval, input, 8) == 0) + printf("local var memcmp works!\n"); + else if (memcmp(shortval, input, 4) == 0) + printf("short local var memcmp works!\n"); + else if (memcmp(global_cmpval, input, sizeof(global_cmpval)) == 0) + printf("global var memcmp works!\n"); else printf("I do not know your string\n"); -- cgit 1.4.1 From 5e09e13ece5f074765df65bdec0482509bc23637 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 10:58:58 +0200 Subject: m32/m64 support for LTO and code-format for test/ --- llvm_mode/GNUmakefile | 3 ++- llvm_mode/afl-clang-fast.c | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 2bbc92c8..57da03f8 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -273,7 +273,8 @@ 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 + $(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o + @$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi endif # laf diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index fa76a11e..2114ccf3 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -479,18 +479,19 @@ 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) { case 0: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt%s.o", obj_path, + instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); break; case 32: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt%s-32.o", obj_path, + instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); if (access(cc_params[cc_par_cnt - 1], R_OK)) FATAL("-m32 is not supported by your compiler"); @@ -498,7 +499,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { break; case 64: - cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt%s-64.o", obj_path, + instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); if (access(cc_params[cc_par_cnt - 1], R_OK)) FATAL("-m64 is not supported by your compiler"); -- cgit 1.4.1 From 4ed43b7632e8e0d80230bd3c27ee7f4d536a543a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 11:00:01 +0200 Subject: m32/m64 support for LTO and code-format for test/ --- llvm_mode/GNUmakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 57da03f8..643c6ef8 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -320,7 +320,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 ../afl-llvm-rt-lto.o ../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 -- cgit 1.4.1 From 0a525f768b8b50e6f20a59489f19a4efe84ccfff Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 12:13:01 +0200 Subject: local/global var for compare-transform-pass and code-format --- GNUmakefile | 1 + llvm_mode/afl-clang-fast.c | 8 +- llvm_mode/compare-transform-pass.so.cc | 143 ++++++++++++++++++++++++++++++--- test/test-compcov.c | 15 +++- test/test-custom-mutator.c | 19 ++--- test/test-unsigaction.c | 50 +++++++----- 6 files changed, 185 insertions(+), 51 deletions(-) (limited to 'llvm_mode') diff --git a/GNUmakefile b/GNUmakefile index 00b357f9..a3ac2e06 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -360,6 +360,7 @@ code-format: ./.custom-format.py -i gcc_plugin/*.cc ./.custom-format.py -i examples/*/*.c ./.custom-format.py -i examples/*/*.h + ./.custom-format.py -i test/*.c ./.custom-format.py -i qemu_mode/patches/*.h ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 2114ccf3..080c7838 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -401,9 +401,11 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (getenv("AFL_NO_BUILTIN") || (instrument_mode == INSTRUMENT_LTO && - (getenv("AFL_LLVM_LTO_AUTODICTIONARY") || - getenv("AFL_LLVM_AUTODICTIONARY")))) { + if (getenv("AFL_NO_BUILTIN") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES") || + getenv("LAF_TRANSFORM_COMPARES") || + (instrument_mode == INSTRUMENT_LTO && + (getenv("AFL_LLVM_LTO_AUTODICTIONARY") || + getenv("AFL_LLVM_AUTODICTIONARY")))) { cc_params[cc_par_cnt++] = "-fno-builtin-strcmp"; cc_params[cc_par_cnt++] = "-fno-builtin-strncmp"; diff --git a/llvm_mode/compare-transform-pass.so.cc b/llvm_mode/compare-transform-pass.so.cc index 2ca70659..84a9b8d9 100644 --- a/llvm_mode/compare-transform-pass.so.cc +++ b/llvm_mode/compare-transform-pass.so.cc @@ -112,11 +112,12 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, const bool processStrcasecmp, const bool processStrncasecmp) { - std::vector calls; - LLVMContext & C = M.getContext(); - IntegerType * Int8Ty = IntegerType::getInt8Ty(C); - IntegerType * Int32Ty = IntegerType::getInt32Ty(C); - IntegerType * Int64Ty = IntegerType::getInt64Ty(C); + DenseMap valueMap; + std::vector calls; + LLVMContext & C = M.getContext(); + IntegerType * Int8Ty = IntegerType::getInt8Ty(C); + IntegerType * Int32Ty = IntegerType::getInt32Ty(C); + IntegerType * Int64Ty = IntegerType::getInt64Ty(C); #if LLVM_VERSION_MAJOR < 9 Constant * @@ -263,6 +264,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, bool isStrncmp = processStrncmp; bool isStrcasecmp = processStrcasecmp; bool isStrncasecmp = processStrncasecmp; + bool isIntMemcpy = true; + bool indirect = false; Function *Callee = callInst->getCalledFunction(); if (!Callee) continue; @@ -273,9 +276,10 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, isStrncmp &= !FuncName.compare(StringRef("strncmp")); isStrcasecmp &= !FuncName.compare(StringRef("strcasecmp")); isStrncasecmp &= !FuncName.compare(StringRef("strncasecmp")); + isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64"); if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && - !isStrncasecmp) + !isStrncasecmp && !isIntMemcpy) continue; /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function @@ -309,7 +313,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, FT->getParamType(2)->isIntegerTy(); if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp && - !isStrncasecmp) + !isStrncasecmp && !isIntMemcpy) continue; /* is a str{n,}{case,}cmp/memcmp, check if we have @@ -322,6 +326,97 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, bool HasStr1 = getConstantStringInfo(Str1P, Str1); bool HasStr2 = getConstantStringInfo(Str2P, Str2); + if (isIntMemcpy && HasStr2) { + + valueMap[Str1P] = new std::string(Str2.str()); + // fprintf(stderr, "saved %s for %p\n", Str2.str().c_str(), Str1P); + continue; + + } + + // not literal? maybe global or local variable + if (!(HasStr1 ^ HasStr2)) { + + auto *Ptr = dyn_cast(Str2P); + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast(Ptr->getOperand(0))) { + + if (auto *Array = + dyn_cast(Var->getInitializer())) { + + HasStr2 = true; + Str2 = Array->getAsString(); + valueMap[Str2P] = new std::string(Str2.str()); + // fprintf(stderr, "glo2 %s\n", Str2.str().c_str()); + + } + + } + + } + + if (!HasStr2) { + + auto *Ptr = dyn_cast(Str1P); + if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) { + + if (auto *Var = dyn_cast(Ptr->getOperand(0))) { + + if (auto *Array = + dyn_cast(Var->getInitializer())) { + + HasStr1 = true; + Str1 = Array->getAsString(); + valueMap[Str1P] = new std::string(Str1.str()); + // fprintf(stderr, "glo1 %s\n", Str1.str().c_str()); + + } + + } + + } + + } else if (isIntMemcpy) { + + valueMap[Str1P] = new std::string(Str2.str()); + // fprintf(stderr, "saved\n"); + + } + + if ((HasStr1 ^ HasStr2)) indirect = true; + + } + + if (isIntMemcpy) continue; + + if (!(HasStr1 ^ HasStr2)) { + + // do we have a saved local variable initialization? + std::string *val = valueMap[Str1P]; + if (val && !val->empty()) { + + Str1 = StringRef(*val); + HasStr1 = true; + indirect = true; + // fprintf(stderr, "loaded1 %s\n", Str1.str().c_str()); + + } else { + + val = valueMap[Str2P]; + if (val && !val->empty()) { + + Str2 = StringRef(*val); + HasStr2 = true; + indirect = true; + // fprintf(stderr, "loaded2 %s\n", Str2.str().c_str()); + + } + + } + + } + /* handle cases of one string is const, one string is variable */ if (!(HasStr1 ^ HasStr2)) continue; @@ -334,9 +429,8 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, 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; + uint64_t literalLength = HasStr1 ? Str1.size() : Str2.size(); + if (literalLength + 1 < ilen->getZExtValue()) continue; } @@ -363,9 +457,9 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, std::string TmpConstStr; Value * VarStr; bool HasStr1 = getConstantStringInfo(Str1P, Str1); - getConstantStringInfo(Str2P, Str2); - uint64_t constLen, sizedLen; - bool isMemcmp = + bool HasStr2 = getConstantStringInfo(Str2P, Str2); + uint64_t constLen, sizedLen; + bool isMemcmp = !callInst->getCalledFunction()->getName().compare(StringRef("memcmp")); bool isSizedcmp = isMemcmp || !callInst->getCalledFunction()->getName().compare( @@ -389,6 +483,29 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } + if (!(HasStr1 ^ HasStr2)) { + + // do we have a saved local or global variable initialization? + std::string *val = valueMap[Str1P]; + if (val && !val->empty()) { + + Str1 = StringRef(*val); + HasStr1 = true; + + } else { + + val = valueMap[Str2P]; + if (val && !val->empty()) { + + Str2 = StringRef(*val); + HasStr2 = true; + + } + + } + + } + if (HasStr1) { TmpConstStr = Str1.str(); diff --git a/test/test-compcov.c b/test/test-compcov.c index fff9c759..f1743265 100644 --- a/test/test-compcov.c +++ b/test/test-compcov.c @@ -6,27 +6,33 @@ char global_cmpval[] = "GLOBALVARIABLE"; int main(int argc, char **argv) { + char *input = argv[1], *buf, buffer[20]; - char cmpval[] = "LOCALVARIABLE"; - char shortval[4] = "abc"; + char cmpval[] = "LOCALVARIABLE"; + char shortval[4] = "abc"; if (argc < 2) { + ssize_t ret = read(0, buffer, sizeof(buffer) - 1); buffer[ret] = 0; input = buffer; + } - + if (strcmp(input, "LIBTOKENCAP") == 0) printf("your string was libtokencap\n"); else if (strcmp(input, "BUGMENOT") == 0) printf("your string was bugmenot\n"); else if (strcmp(input, "BUFFEROVERFLOW") == 0) { + buf = malloc(16); strcpy(buf, "TEST"); strcat(buf, input); printf("This will only crash with libdislocator: %s\n", buf); return 0; - } else if (*(unsigned int*)input == 0xabadcafe) + + } else if (*(unsigned int *)input == 0xabadcafe) + printf("GG you eat cmp tokens for breakfast!\n"); else if (memcmp(cmpval, input, 8) == 0) printf("local var memcmp works!\n"); @@ -40,3 +46,4 @@ int main(int argc, char **argv) { return 0; } + diff --git a/test/test-custom-mutator.c b/test/test-custom-mutator.c index 83baafab..f868550c 100644 --- a/test/test-custom-mutator.c +++ b/test/test-custom-mutator.c @@ -1,5 +1,6 @@ /** - * Reference: https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c + * Reference: + * https://github.com/bruce30262/libprotobuf-mutator_fuzzing_learning/blob/master/4_libprotobuf_aflpp_custom_mutator/vuln.c */ #include @@ -8,12 +9,12 @@ #include #include -int main(int argc, char *argv[]) -{ - char str[100]; - read(0, str, 100); - if( str[6] == 'A') { - abort(); - } - return 0; +int main(int argc, char *argv[]) { + + char str[100]; + read(0, str, 100); + if (str[6] == 'A') { abort(); } + return 0; + } + diff --git a/test/test-unsigaction.c b/test/test-unsigaction.c index 1a5e4b26..8c6c7f41 100644 --- a/test/test-unsigaction.c +++ b/test/test-unsigaction.c @@ -1,25 +1,31 @@ -#include /* sigemptyset(), sigaction(), kill(), SIGUSR1 */ -#include /* exit() */ -#include /* getpid() */ -#include /* errno */ -#include /* fprintf() */ - -static void mysig_handler(int sig) -{ - exit(2); +#include /* sigemptyset(), sigaction(), kill(), SIGUSR1 */ +#include /* exit() */ +#include /* getpid() */ +#include /* errno */ +#include /* fprintf() */ + +static void mysig_handler(int sig) { + + exit(2); + } -int main() -{ - /* setup sig handler */ - struct sigaction sa; - sa.sa_handler = mysig_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - if (sigaction(SIGCHLD, &sa, NULL)) { - fprintf(stderr, "could not set signal handler %d, aborted\n", errno); - exit(1); - } - kill(getpid(), SIGCHLD); - return 0; +int main() { + + /* setup sig handler */ + struct sigaction sa; + sa.sa_handler = mysig_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGCHLD, &sa, NULL)) { + + fprintf(stderr, "could not set signal handler %d, aborted\n", errno); + exit(1); + + } + + kill(getpid(), SIGCHLD); + return 0; + } + -- cgit 1.4.1 From ec677808549c19d22431539ff9a13498c907b4c9 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 14:04:17 +0200 Subject: fix 32/64 bit LTO --- llvm_mode/GNUmakefile | 3 ++- llvm_mode/afl-clang-fast.c | 33 ++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 12 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index 643c6ef8..e004de03 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -275,6 +275,7 @@ ifeq "$(LLVM_LTO)" "1" $(CXX) $(CLANG_CFL) -Wno-writable-strings -fno-rtti -fPIC -std=$(LLVM_STDCXX) -shared $< -o $@ $(CLANG_LFL) $(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto.o @$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m64 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-64.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi + @$(CC) $(CFLAGS) -Wno-unused-result -O0 $(AFL_CLANG_FLTO) -m32 -fPIC -c afl-llvm-rt-lto.o.c -o ../afl-llvm-rt-lto-32.o 2>/dev/null; if [ "$$?" = "0" ]; then : ; fi endif # laf @@ -360,4 +361,4 @@ endif clean: rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1 *.dwo - rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld + rm -f $(PROGS) afl-common.o ../afl-clang-fast++ ../afl-clang-lto ../afl-clang-lto++ ../afl-clang*.8 ../ld ../afl-ld ../afl-llvm-rt*.o diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 080c7838..b7ef1858 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -485,28 +485,39 @@ static void edit_params(u32 argc, char **argv, char **envp) { switch (bit_mode) { case 0: - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt%s.o", obj_path, - instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt.o", obj_path); + if (instrument_mode == INSTRUMENT_LTO) + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto.o", obj_path); break; case 32: - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt%s-32.o", obj_path, - instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); - + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-32.o", obj_path); if (access(cc_params[cc_par_cnt - 1], R_OK)) FATAL("-m32 is not supported by your compiler"); + if (instrument_mode == INSTRUMENT_LTO) { + + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto-32.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m32 is not supported by your compiler"); + + } break; case 64: - cc_params[cc_par_cnt++] = - alloc_printf("%s/afl-llvm-rt%s-64.o", obj_path, - instrument_mode == INSTRUMENT_LTO ? "-lto" : ""); - + cc_params[cc_par_cnt++] = alloc_printf("%s/afl-llvm-rt-64.o", obj_path); if (access(cc_params[cc_par_cnt - 1], R_OK)) FATAL("-m64 is not supported by your compiler"); + if (instrument_mode == INSTRUMENT_LTO) { + + cc_params[cc_par_cnt++] = + alloc_printf("%s/afl-llvm-rt-lto-64.o", obj_path); + if (access(cc_params[cc_par_cnt - 1], R_OK)) + FATAL("-m64 is not supported by your compiler"); + + } break; -- cgit 1.4.1 From e70c54547e7046a3a5cc7c345f22b684bf236b5d Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sun, 12 Apr 2020 17:23:41 +0200 Subject: remove warnings with llvm11 --- llvm_mode/GNUmakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index e004de03..d6a00580 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -294,15 +294,15 @@ endif $(CXX) $(CLANG_CFL) -shared $< -o $@ $(CLANG_LFL) ../afl-llvm-rt.o: afl-llvm-rt.o.c | test_deps - $(CC) $(CFLAGS) -fPIC -c $< -o $@ + $(CC) $(CFLAGS) -Wno-unused-result -fPIC -c $< -o $@ ../afl-llvm-rt-32.o: afl-llvm-rt.o.c | test_deps @printf "[*] Building 32-bit variant of the runtime (-m32)... " - @$(CC) $(CFLAGS) -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @$(CC) $(CFLAGS) -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi ../afl-llvm-rt-64.o: afl-llvm-rt.o.c | test_deps @printf "[*] Building 64-bit variant of the runtime (-m64)... " - @$(CC) $(CFLAGS) -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi + @$(CC) $(CFLAGS) -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi test_build: $(PROGS) @echo "[*] Testing the CC wrapper and instrumentation output..." -- cgit 1.4.1 From 4b88e059efb29e21290bfae9ebae8f9521e2e91c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 13 Apr 2020 17:05:43 +0200 Subject: more robust search for clang for afl-clang-fast --- llvm_mode/GNUmakefile | 20 +++++++++++++++++--- llvm_mode/afl-clang-fast.c | 11 ++++------- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/GNUmakefile b/llvm_mode/GNUmakefile index d6a00580..67c31f14 100644 --- a/llvm_mode/GNUmakefile +++ b/llvm_mode/GNUmakefile @@ -82,8 +82,8 @@ endif # this seems to be busted on some distros, so using the one in $PATH is # probably better. -CC = $(LLVM_BINDIR)/clang -CXX = $(LLVM_BINDIR)/clang++ +CC ?= $(LLVM_BINDIR)/clang +CXX ?= $(LLVM_BINDIR)/clang++ ifeq "$(shell test -e $(CC) || echo 1 )" "1" # llvm-config --bindir may not providing a valid path, so ... @@ -146,13 +146,27 @@ ifeq "$(shell echo 'int main() {return 0; }' | $(CC) -x c - -fuse-ld=`command -v endif endif +CLANG_BIN = $(basename $(CC)) +CLANGPP_BIN = $(basename $(CXX)) +ifeq "$(shell test -e $(CLANG_BIN) || echo 1 )" "1" + CLANG_BIN = $(CC) + CLANGPP_BIN = $(CXX) +endif + +ifeq "$(CC)" "$(LLVM_BINDIR)/clang" + USE_BINDIR = 1 +else + USE_BINDIR = 0 +endif + CFLAGS ?= -O3 -funroll-loops -D_FORTIFY_SOURCE=2 override CFLAGS += -Wall \ -g -Wno-pointer-sign -I ../include/ \ -DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \ -DLLVM_BINDIR=\"$(LLVM_BINDIR)\" -DVERSION=\"$(VERSION)\" \ -DLLVM_VERSION=\"$(LLVMVER)\" -DAFL_CLANG_FLTO=\"$(AFL_CLANG_FLTO)\" \ - -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" -Wno-unused-function + -DAFL_REAL_LD=\"$(AFL_REAL_LD)\" -DAFL_CLANG_FUSELD=\"$(AFL_CLANG_FUSELD)\" \ + -DCLANG_BIN=\"$(CC)\" -DCLANGPP_BIN=\"$(CXX)\" -DUSE_BINDIR=$(USE_BINDIR) -Wno-unused-function ifdef AFL_TRACE_PC $(info Compile option AFL_TRACE_PC is deprecated, just set AFL_LLVM_INSTRUMENT=PCGUARD to activate when compiling targets ) endif diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index b7ef1858..52a4829c 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -159,7 +159,6 @@ static void find_obj(u8 *argv0) { static void edit_params(u32 argc, char **argv, char **envp) { u8 fortify_set = 0, asan_set = 0, x_set = 0, bit_mode = 0; - u8 has_llvm_config = 0; u8 *name; cc_params = ck_alloc((argc + 128) * sizeof(u8 *)); @@ -170,8 +169,6 @@ static void edit_params(u32 argc, char **argv, char **envp) { else ++name; - has_llvm_config = (strlen(LLVM_BINDIR) > 0); - if (instrument_mode == INSTRUMENT_LTO) if (lto_flag[0] != '-') FATAL( @@ -181,19 +178,19 @@ static void edit_params(u32 argc, char **argv, char **envp) { if (!strcmp(name, "afl-clang-fast++") || !strcmp(name, "afl-clang-lto++")) { u8 *alt_cxx = getenv("AFL_CXX"); - if (has_llvm_config) + if (USE_BINDIR) snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang++", LLVM_BINDIR); else - sprintf(llvm_fullpath, "clang++"); + sprintf(llvm_fullpath, CLANGPP_BIN); cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; } else { u8 *alt_cc = getenv("AFL_CC"); - if (has_llvm_config) + if (USE_BINDIR) snprintf(llvm_fullpath, sizeof(llvm_fullpath), "%s/clang", LLVM_BINDIR); else - sprintf(llvm_fullpath, "clang"); + sprintf(llvm_fullpath, CLANG_BIN); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath; } -- cgit 1.4.1 From b1e7b834aca1133d4f19314149d38c87dd295147 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 14 Apr 2020 11:24:53 +0200 Subject: add missing default names for AFL_LLVM_INSTRUMENT --- llvm_mode/afl-clang-fast.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 52a4829c..b121ea97 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -548,6 +548,10 @@ int main(int argc, char **argv, char **envp) { if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) { + if (strncasecmp(ptr, "default", strlen("default")) == 0 || + strncasecmp(ptr, "afl", strlen("afl")) == 0 || + strncasecmp(ptr, "classic", strlen("classic")) == 0 ) + instrument_mode = INSTRUMENT_DEFAULT; if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr, "instrim", strlen("instrim")) == 0) instrument_mode = INSTRUMENT_CFG; -- cgit 1.4.1 From 92aaaef38126853f26e1be0e522a29c974e24bb5 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 14 Apr 2020 12:42:38 +0200 Subject: code format --- include/afl-fuzz.h | 9 ++- llvm_mode/afl-clang-fast.c | 4 +- src/afl-fuzz-one.c | 3 +- src/afl-fuzz-redqueen.c | 138 +++++++++++++++++++++++++++------------------ src/afl-fuzz-state.c | 2 +- src/afl-fuzz-stats.c | 14 ++--- 6 files changed, 101 insertions(+), 69 deletions(-) (limited to 'llvm_mode') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 9da9452a..3df99a58 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -341,7 +341,10 @@ typedef struct afl_env_vars { } afl_env_vars_t; struct afl_pass_stat { - u8 total; u8 faileds; + + u8 total; + u8 faileds; + }; typedef struct afl_state { @@ -573,8 +576,8 @@ typedef struct afl_state { s32 cmplog_fsrv_ctl_fd, cmplog_fsrv_st_fd; u32 cmplog_prev_timed_out; - struct afl_pass_stat* pass_stats; - struct cmp_map *orig_cmp_map; + struct afl_pass_stat *pass_stats; + struct cmp_map * orig_cmp_map; u8 describe_op_buf_256[256]; /* describe_op will use this to return a string up to 256 */ diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index b121ea97..49318f2e 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -549,8 +549,8 @@ int main(int argc, char **argv, char **envp) { if ((ptr = getenv("AFL_LLVM_INSTRUMENT")) != NULL) { if (strncasecmp(ptr, "default", strlen("default")) == 0 || - strncasecmp(ptr, "afl", strlen("afl")) == 0 || - strncasecmp(ptr, "classic", strlen("classic")) == 0 ) + strncasecmp(ptr, "afl", strlen("afl")) == 0 || + strncasecmp(ptr, "classic", strlen("classic")) == 0) instrument_mode = INSTRUMENT_DEFAULT; if (strncasecmp(ptr, "cfg", strlen("cfg")) == 0 || strncasecmp(ptr, "instrim", strlen("instrim")) == 0) diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 65075db4..961a29d6 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -2543,7 +2543,7 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { goto pacemaker_fuzzing; } - + /* Skip right away if -d is given, if we have done deterministic fuzzing on this entry ourselves (was_fuzzed), or if it has gone through deterministic testing in earlier, resumed runs (passed_det). */ @@ -2559,7 +2559,6 @@ u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { (afl->queue_cur->exec_cksum % afl->master_max) != afl->master_id - 1) goto havoc_stage; - doing_det = 1; /********************************************* diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index c8d5565f..0a97e3ee 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -234,15 +234,18 @@ static u8 its_fuzz(afl_state_t *afl, u8 *buf, u32 len, u8 *status) { } -static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 pattern, u64 repl, u64 o_pattern, u32 idx, u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse, u8 *status) { +static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, + u64 pattern, u64 repl, u64 o_pattern, u32 idx, + u8 *orig_buf, u8 *buf, u32 len, u8 do_reverse, + u8 *status) { u64 *buf_64 = (u64 *)&buf[idx]; u32 *buf_32 = (u32 *)&buf[idx]; u16 *buf_16 = (u16 *)&buf[idx]; // u8* buf_8 = &buf[idx]; - u64* o_buf_64 = (u64*)&orig_buf[idx]; - u32* o_buf_32 = (u32*)&orig_buf[idx]; - u16* o_buf_16 = (u16*)&orig_buf[idx]; + u64 *o_buf_64 = (u64 *)&orig_buf[idx]; + u32 *o_buf_32 = (u32 *)&orig_buf[idx]; + u16 *o_buf_16 = (u16 *)&orig_buf[idx]; // u8* o_buf_8 = &orig_buf[idx]; u32 its_len = len - idx; @@ -260,15 +263,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 patter // reverse encoding if (do_reverse) - if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), SWAP64(o_pattern), idx, orig_buf, buf, len, 0, status))) + if (unlikely(cmp_extend_encoding(afl, h, SWAP64(pattern), SWAP64(repl), + SWAP64(o_pattern), idx, orig_buf, buf, + len, 0, status))) return 1; } if (SHAPE_BYTES(h->shape) == 4 || *status == 2) { - if (its_len >= 4 && - *buf_32 == (u32)pattern && *o_buf_32 == (u32)o_pattern) { + if (its_len >= 4 && *buf_32 == (u32)pattern && + *o_buf_32 == (u32)o_pattern) { *buf_32 = (u32)repl; if (unlikely(its_fuzz(afl, buf, len, status))) return 1; @@ -278,15 +283,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 patter // reverse encoding if (do_reverse) - if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), SWAP32(o_pattern), idx, orig_buf, buf, len, 0, status))) + if (unlikely(cmp_extend_encoding(afl, h, SWAP32(pattern), SWAP32(repl), + SWAP32(o_pattern), idx, orig_buf, buf, + len, 0, status))) return 1; } if (SHAPE_BYTES(h->shape) == 2 || *status == 2) { - if (its_len >= 2 && - *buf_16 == (u16)pattern && *o_buf_16 == (u16)o_pattern) { + if (its_len >= 2 && *buf_16 == (u16)pattern && + *o_buf_16 == (u16)o_pattern) { *buf_16 = (u16)repl; if (unlikely(its_fuzz(afl, buf, len, status))) return 1; @@ -296,7 +303,9 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 patter // reverse encoding if (do_reverse) - if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), SWAP16(o_pattern), idx, orig_buf, buf, len, 0, status))) + if (unlikely(cmp_extend_encoding(afl, h, SWAP16(pattern), SWAP16(repl), + SWAP16(o_pattern), idx, orig_buf, buf, + len, 0, status))) return 1; } @@ -371,35 +380,39 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { u8 status; // opt not in the paper u32 fails; - u8 found_one = 0; - + u8 found_one = 0; + /* loop cmps are useless, detect and blacklist them */ u64 s_v0, s_v1; - u8 s_v0_fixed = 1, s_v1_fixed = 1; - u8 s_v0_inc = 1, s_v1_inc = 1; - u8 s_v0_dec = 1, s_v1_dec = 1; + u8 s_v0_fixed = 1, s_v1_fixed = 1; + u8 s_v0_inc = 1, s_v1_inc = 1; + u8 s_v0_dec = 1, s_v1_dec = 1; for (i = 0; i < loggeds; ++i) { - + fails = 0; struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; - + // loop detection code if (i == 0) { + s_v0 = o->v0; s_v1 = o->v1; + } else { + if (s_v0 != o->v0) s_v0_fixed = 0; if (s_v1 != o->v1) s_v1_fixed = 0; - if (s_v0 +1 != o->v0) s_v0_inc = 0; - if (s_v1 +1 != o->v1) s_v1_inc = 0; - if (s_v0 -1 != o->v0) s_v0_dec = 0; - if (s_v1 -1 != o->v1) s_v1_dec = 0; + if (s_v0 + 1 != o->v0) s_v0_inc = 0; + if (s_v1 + 1 != o->v1) s_v1_inc = 0; + if (s_v0 - 1 != o->v0) s_v0_dec = 0; + if (s_v1 - 1 != o->v1) s_v1_dec = 0; s_v0 = o->v0; s_v1 = o->v1; + } - + struct cmp_operands *orig_o = &afl->orig_cmp_map->log[key][i]; // opt not in the paper @@ -410,14 +423,16 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { for (idx = 0; idx < len && fails < 8; ++idx) { - if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, orig_buf, buf, len, 1, &status))) + if (unlikely(cmp_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, + orig_buf, buf, len, 1, &status))) return 1; if (status == 2) ++fails; else if (status == 1) break; - if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, orig_buf, buf, len, 1, &status))) + if (unlikely(cmp_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, + orig_buf, buf, len, 1, &status))) return 1; if (status == 2) ++fails; @@ -425,16 +440,17 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { break; } - - if (status == 1) - found_one = 1; + + if (status == 1) found_one = 1; // If failed, add to dictionary if (fails == 8) { if (afl->pass_stats[key].total == 0) { + try_to_add_to_dict(afl, o->v0, SHAPE_BYTES(h->shape)); try_to_add_to_dict(afl, o->v1, SHAPE_BYTES(h->shape)); + } } @@ -443,22 +459,29 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { afl->stage_cur++; } - + if (loggeds > 3 && ((s_v0_fixed && s_v1_inc) || (s_v1_fixed && s_v0_inc) || (s_v0_fixed && s_v1_dec) || (s_v1_fixed && s_v0_dec))) { + afl->pass_stats[key].total = afl->pass_stats[key].faileds = 0xff; + } - + if (!found_one && afl->pass_stats[key].faileds < 0xff) { + afl->pass_stats[key].faileds++; + } + if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++; return 0; } -static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h, u8 *pattern, u8 *repl, u8* o_pattern, u32 idx, u8 *orig_buf, u8 *buf, u32 len, u8 *status) { +static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h, + u8 *pattern, u8 *repl, u8 *o_pattern, u32 idx, + u8 *orig_buf, u8 *buf, u32 len, u8 *status) { u32 i; u32 its_len = MIN(32, len - idx); @@ -470,7 +493,9 @@ static u8 rtn_extend_encoding(afl_state_t *afl, struct cmp_header *h, u8 *patter for (i = 0; i < its_len; ++i) { - if (pattern[idx + i] != buf[idx + i] || o_pattern[idx + i] != orig_buf[idx + i] || *status == 1) break; + if (pattern[idx + i] != buf[idx + i] || + o_pattern[idx + i] != orig_buf[idx + i] || *status == 1) + break; buf[idx + i] = repl[idx + i]; if (unlikely(its_fuzz(afl, buf, len, status))) return 1; @@ -493,15 +518,15 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { u8 status = 0; // opt not in the paper u32 fails = 0; - u8 found_one = 0; + u8 found_one = 0; for (i = 0; i < loggeds; ++i) { - + fails = 0; struct cmpfn_operands *o = &((struct cmpfn_operands *)afl->shm.cmp_map->log[key])[i]; - + struct cmpfn_operands *orig_o = &((struct cmpfn_operands *)afl->orig_cmp_map->log[key])[i]; @@ -513,14 +538,16 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { for (idx = 0; idx < len && fails < 8; ++idx) { - if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, orig_buf, buf, len, &status))) + if (unlikely(rtn_extend_encoding(afl, h, o->v0, o->v1, orig_o->v0, idx, + orig_buf, buf, len, &status))) return 1; if (status == 2) ++fails; else if (status == 1) break; - if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, orig_buf, buf, len, &status))) + if (unlikely(rtn_extend_encoding(afl, h, o->v1, o->v0, orig_o->v1, idx, + orig_buf, buf, len, &status))) return 1; if (status == 2) ++fails; @@ -528,16 +555,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { break; } - - if (status == 1) - found_one = 1; + + if (status == 1) found_one = 1; // If failed, add to dictionary if (fails == 8) { if (afl->pass_stats[key].total == 0) { + maybe_add_auto((u8 *)afl, o->v0, SHAPE_BYTES(h->shape)); maybe_add_auto((u8 *)afl, o->v1, SHAPE_BYTES(h->shape)); + } } @@ -546,10 +574,13 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u32 len) { afl->stage_cur++; } - + if (!found_one && afl->pass_stats[key].faileds < 0xff) { + afl->pass_stats[key].faileds++; + } + if (afl->pass_stats[key].total < 0xff) afl->pass_stats[key].total++; return 0; @@ -565,13 +596,13 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, u8 r = 1; if (afl->orig_cmp_map == NULL) afl->orig_cmp_map = ck_alloc_nozero(sizeof(struct cmp_map)); - + if (afl->pass_stats == NULL) afl->pass_stats = ck_alloc(sizeof(struct afl_pass_stat) * CMP_MAP_W); - + // do it manually, forkserver clear only afl->fsrv.trace_bits memset(afl->shm.cmp_map->headers, 0, sizeof(afl->shm.cmp_map->headers)); - + if (unlikely(common_fuzz_cmplog_stuff(afl, buf, len))) return 1; memcpy(afl->orig_cmp_map, afl->shm.cmp_map, sizeof(struct cmp_map)); @@ -596,12 +627,13 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, for (k = 0; k < CMP_MAP_W; ++k) { if (!afl->shm.cmp_map->headers[k].hits) continue; - + if (afl->pass_stats[k].total && - (rand_below(afl, afl->pass_stats[k].total) >= afl->pass_stats[k].faileds - || afl->pass_stats[k].total == 0xff)) - afl->shm.cmp_map->headers[k].hits = 0; // blacklist this cmp - + (rand_below(afl, afl->pass_stats[k].total) >= + afl->pass_stats[k].faileds || + afl->pass_stats[k].total == 0xff)) + afl->shm.cmp_map->headers[k].hits = 0; // blacklist this cmp + if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) afl->stage_max += MIN((u32)afl->shm.cmp_map->headers[k].hits, CMP_MAP_H); else @@ -616,13 +648,11 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len, if (afl->shm.cmp_map->headers[k].type == CMP_TYPE_INS) { - if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, len))) - goto exit_its; + if (unlikely(cmp_fuzz(afl, k, orig_buf, buf, len))) goto exit_its; } else { - if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, len))) - goto exit_its; + if (unlikely(rtn_fuzz(afl, k, orig_buf, buf, len))) goto exit_its; } @@ -634,7 +664,7 @@ exit_its: new_hit_cnt = afl->queued_paths + afl->unique_crashes; afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt; afl->stage_cycles[STAGE_ITS] += afl->total_execs - orig_execs; - + memcpy(orig_buf, buf, len); return r; diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 87d74afa..7664c521 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -370,7 +370,7 @@ void afl_state_deinit(afl_state_t *afl) { free(afl->in_buf); free(afl->in_scratch_buf); free(afl->ex_buf); - + list_remove(&afl_states, afl); } diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d48dd5e3..d42df2db 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -387,9 +387,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) { @@ -471,9 +471,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 @@ -503,9 +503,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); @@ -579,7 +579,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"); -- cgit 1.4.1 From 0d0338012beb320dcfcaa3d16ae78da47dd48b80 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 14 Apr 2020 13:02:49 +0200 Subject: one byte cmp in cmplog --- llvm_mode/afl-llvm-rt.o.c | 65 +++++++++++++++----------- qemu_mode/patches/afl-qemu-cpu-translate-inl.h | 5 +- qemu_mode/patches/afl-qemu-tcg-runtime-inl.h | 27 ++++++++++- qemu_mode/patches/tcg-runtime-head.diff | 3 +- src/afl-fuzz-redqueen.c | 15 +++--- 5 files changed, 77 insertions(+), 38 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 3ad9eab4..89879a42 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -651,13 +651,29 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { ///// CmpLog instrumentation -void __cmplog_ins_hook1(uint8_t Arg1, uint8_t Arg2) { +void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) { - return; + if (!__afl_cmp_map) return; + + uintptr_t k = (uintptr_t)__builtin_return_address(0); + k = (k >> 4) ^ (k << 8); + k &= CMP_MAP_W - 1; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + // if (!__afl_cmp_map->headers[k].cnt) + // __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++; + __afl_cmp_map->headers[k].shape = 0; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; } -void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) { +void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) { if (!__afl_cmp_map) return; @@ -669,19 +685,16 @@ void __cmplog_ins_hook2(uint16_t Arg1, uint16_t Arg2) { u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; - // if (!__afl_cmp_map->headers[k].cnt) - // __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++; __afl_cmp_map->headers[k].shape = 1; - //__afl_cmp_map->headers[k].type = CMP_TYPE_INS; hits &= CMP_MAP_H - 1; - __afl_cmp_map->log[k][hits].v0 = Arg1; - __afl_cmp_map->log[k][hits].v1 = Arg2; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; } -void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) { +void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2) { if (!__afl_cmp_map) return; @@ -697,12 +710,12 @@ void __cmplog_ins_hook4(uint32_t Arg1, uint32_t Arg2) { __afl_cmp_map->headers[k].shape = 3; hits &= CMP_MAP_H - 1; - __afl_cmp_map->log[k][hits].v0 = Arg1; - __afl_cmp_map->log[k][hits].v1 = Arg2; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; } -void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) { +void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) { if (!__afl_cmp_map) return; @@ -718,8 +731,8 @@ void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) { __afl_cmp_map->headers[k].shape = 7; hits &= CMP_MAP_H - 1; - __afl_cmp_map->log[k][hits].v0 = Arg1; - __afl_cmp_map->log[k][hits].v1 = Arg2; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; } @@ -734,28 +747,28 @@ void __cmplog_ins_hook8(uint64_t Arg1, uint64_t Arg2) { #pragma weak __sanitizer_cov_trace_cmp4 = __cmplog_ins_hook4 #pragma weak __sanitizer_cov_trace_cmp8 = __cmplog_ins_hook8 #else -void __sanitizer_cov_trace_const_cmp1(uint8_t Arg1, uint8_t Arg2) +void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__cmplog_ins_hook1"))); -void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2) +void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2) __attribute__((alias("__cmplog_ins_hook2"))); -void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2) +void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2) __attribute__((alias("__cmplog_ins_hook4"))); -void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2) +void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2) __attribute__((alias("__cmplog_ins_hook8"))); -void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) +void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__cmplog_ins_hook1"))); -void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) +void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) __attribute__((alias("__cmplog_ins_hook2"))); -void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) +void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) __attribute__((alias("__cmplog_ins_hook4"))); -void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) +void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) __attribute__((alias("__cmplog_ins_hook8"))); #endif /* defined(__APPLE__) */ -void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { +void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { - for (uint64_t i = 0; i < Cases[0]; i++) { + for (uint64_t i = 0; i < cases[0]; i++) { uintptr_t k = (uintptr_t)__builtin_return_address(0) + i; k = (k >> 4) ^ (k << 8); @@ -769,8 +782,8 @@ void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) { __afl_cmp_map->headers[k].shape = 7; hits &= CMP_MAP_H - 1; - __afl_cmp_map->log[k][hits].v0 = Val; - __afl_cmp_map->log[k][hits].v1 = Cases[i + 2]; + __afl_cmp_map->log[k][hits].v0 = val; + __afl_cmp_map->log[k][hits].v1 = cases[i + 2]; } diff --git a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h index 72353967..1abec477 100644 --- a/qemu_mode/patches/afl-qemu-cpu-translate-inl.h +++ b/qemu_mode/patches/afl-qemu-cpu-translate-inl.h @@ -53,11 +53,12 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2, TCGv cur_loc_v = tcg_const_tl(cur_loc); - switch (ot) { + switch (ot & MO_SIZE) { case MO_64: gen_helper_afl_cmplog_64(cur_loc_v, arg1, arg2); break; case MO_32: gen_helper_afl_cmplog_32(cur_loc_v, arg1, arg2); break; case MO_16: gen_helper_afl_cmplog_16(cur_loc_v, arg1, arg2); break; + case MO_8: gen_helper_afl_cmplog_8(cur_loc_v, arg1, arg2); break; default: break; } @@ -75,7 +76,7 @@ static void afl_gen_compcov(target_ulong cur_loc, TCGv arg1, TCGv arg2, if (cur_loc >= afl_inst_rms) return; - switch (ot) { + switch (ot & MO_SIZE) { case MO_64: gen_helper_afl_compcov_64(cur_loc_v, arg1, arg2); break; case MO_32: gen_helper_afl_compcov_32(cur_loc_v, arg1, arg2); break; diff --git a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h index 1526f09c..549b6bba 100644 --- a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h +++ b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h @@ -107,18 +107,39 @@ void HELPER(afl_compcov_64)(target_ulong cur_loc, target_ulong arg1, } +void HELPER(afl_cmplog_8)(target_ulong cur_loc, target_ulong arg1, + target_ulong arg2) { + + register uintptr_t k = (uintptr_t)cur_loc; + + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + + u32 hits = __afl_cmp_map->headers[k].hits; + __afl_cmp_map->headers[k].hits = hits + 1; + // if (!__afl_cmp_map->headers[k].cnt) + // __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++; + + __afl_cmp_map->headers[k].shape = 0; + + hits &= CMP_MAP_H - 1; + __afl_cmp_map->log[k][hits].v0 = arg1; + __afl_cmp_map->log[k][hits].v1 = arg2; + +} + void HELPER(afl_cmplog_16)(target_ulong cur_loc, target_ulong arg1, target_ulong arg2) { register uintptr_t k = (uintptr_t)cur_loc; + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; // if (!__afl_cmp_map->headers[k].cnt) // __afl_cmp_map->headers[k].cnt = __afl_cmp_counter++; __afl_cmp_map->headers[k].shape = 1; - //__afl_cmp_map->headers[k].type = CMP_TYPE_INS; hits &= CMP_MAP_H - 1; __afl_cmp_map->log[k][hits].v0 = arg1; @@ -131,6 +152,8 @@ void HELPER(afl_cmplog_32)(target_ulong cur_loc, target_ulong arg1, register uintptr_t k = (uintptr_t)cur_loc; + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; @@ -147,6 +170,8 @@ void HELPER(afl_cmplog_64)(target_ulong cur_loc, target_ulong arg1, register uintptr_t k = (uintptr_t)cur_loc; + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; + u32 hits = __afl_cmp_map->headers[k].hits; __afl_cmp_map->headers[k].hits = hits + 1; diff --git a/qemu_mode/patches/tcg-runtime-head.diff b/qemu_mode/patches/tcg-runtime-head.diff index 626c67ef..f250686e 100644 --- a/qemu_mode/patches/tcg-runtime-head.diff +++ b/qemu_mode/patches/tcg-runtime-head.diff @@ -2,7 +2,7 @@ diff --git a/accel/tcg/tcg-runtime.h b/accel/tcg/tcg-runtime.h index 1bd39d13..81ef3973 100644 --- a/accel/tcg/tcg-runtime.h +++ b/accel/tcg/tcg-runtime.h -@@ -260,3 +260,13 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +@@ -260,3 +260,14 @@ DEF_HELPER_FLAGS_4(gvec_leu8, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu16, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu32, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_4(gvec_leu64, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) @@ -12,6 +12,7 @@ index 1bd39d13..81ef3973 100644 +DEF_HELPER_FLAGS_3(afl_compcov_16, TCG_CALL_NO_RWG, void, tl, tl, tl) +DEF_HELPER_FLAGS_3(afl_compcov_32, TCG_CALL_NO_RWG, void, tl, tl, tl) +DEF_HELPER_FLAGS_3(afl_compcov_64, TCG_CALL_NO_RWG, void, tl, tl, tl) ++DEF_HELPER_FLAGS_3(afl_cmplog_8, TCG_CALL_NO_RWG, void, tl, tl, tl) +DEF_HELPER_FLAGS_3(afl_cmplog_16, TCG_CALL_NO_RWG, void, tl, tl, tl) +DEF_HELPER_FLAGS_3(afl_cmplog_32, TCG_CALL_NO_RWG, void, tl, tl, tl) +DEF_HELPER_FLAGS_3(afl_cmplog_64, TCG_CALL_NO_RWG, void, tl, tl, tl) diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index 0a97e3ee..b80f0c36 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -242,11 +242,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 *buf_64 = (u64 *)&buf[idx]; u32 *buf_32 = (u32 *)&buf[idx]; u16 *buf_16 = (u16 *)&buf[idx]; - // u8* buf_8 = &buf[idx]; + u8* buf_8 = &buf[idx]; u64 *o_buf_64 = (u64 *)&orig_buf[idx]; u32 *o_buf_32 = (u32 *)&orig_buf[idx]; u16 *o_buf_16 = (u16 *)&orig_buf[idx]; - // u8* o_buf_8 = &orig_buf[idx]; + u8* o_buf_8 = &orig_buf[idx]; u32 its_len = len - idx; *status = 0; @@ -310,18 +310,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /*if (SHAPE_BYTES(h->shape) == 1 || *status == 2) { + if (SHAPE_BYTES(h->shape) == 1 || *status == 2) { - if (its_len >= 2 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) { + if (its_len >= 1 && *buf_8 == (u8)pattern && *o_buf_8 == (u8)o_pattern) { *buf_8 = (u8)repl; - if (unlikely(its_fuzz(afl, buf, len, status))) - return 1; - *buf_16 = (u16)pattern; + if (unlikely(its_fuzz(afl, buf, len, status))) return 1; + *buf_8 = (u8)pattern; } - }*/ + } return 0; -- cgit 1.4.1 From f4436f118c7a828e37926b948e997d1c8f5b2b03 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 14 Apr 2020 17:21:15 +0200 Subject: fixed #317 --- llvm_mode/afl-llvm-rt.o.c | 1 + qemu_mode/patches/afl-qemu-tcg-runtime-inl.h | 4 +-- src/afl-fuzz-redqueen.c | 46 ++++++++++++++++------------ src/afl-fuzz-stats.c | 14 ++++----- 4 files changed, 37 insertions(+), 28 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 89879a42..f286e66a 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -671,6 +671,7 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2) { hits &= CMP_MAP_H - 1; __afl_cmp_map->log[k][hits].v0 = arg1; __afl_cmp_map->log[k][hits].v1 = arg2; + } void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2) { diff --git a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h index 549b6bba..a0246198 100644 --- a/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h +++ b/qemu_mode/patches/afl-qemu-tcg-runtime-inl.h @@ -108,10 +108,10 @@ void HELPER(afl_compcov_64)(target_ulong cur_loc, target_ulong arg1, } void HELPER(afl_cmplog_8)(target_ulong cur_loc, target_ulong arg1, - target_ulong arg2) { + target_ulong arg2) { register uintptr_t k = (uintptr_t)cur_loc; - + __afl_cmp_map->headers[k].type = CMP_TYPE_INS; u32 hits = __afl_cmp_map->headers[k].hits; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index ed21e970..6a01ec89 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -121,30 +121,37 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) { afl->stage_cur < afl->stage_max) { u32 s = rng->end - rng->start; - if (s == 0) goto empty_range; - memcpy(backup, buf + rng->start, s); - rand_replace(afl, buf + rng->start, s); + if (s != 0) { - u32 cksum; - u64 start_us = get_cur_time_us(); - if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) goto checksum_fail; - u64 stop_us = get_cur_time_us(); + /* Range not empty */ - /* Discard if the mutations change the paths or if it is too decremental - in speed */ - if (cksum != exec_cksum || - (stop_us - start_us > 2 * afl->queue_cur->exec_us)) { + memcpy(backup, buf + rng->start, s); + rand_replace(afl, buf + rng->start, s); - ranges = add_range(ranges, rng->start, rng->start + s / 2); - ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); - memcpy(buf + rng->start, backup, s); + u32 cksum; + u64 start_us = get_cur_time_us(); + if (unlikely(get_exec_checksum(afl, buf, len, &cksum))) goto checksum_fail; - } else + u64 stop_us = get_cur_time_us(); - needs_write = 1; + /* Discard if the mutations change the paths or if it is too decremental + in speed */ + if (cksum != exec_cksum || + (stop_us - start_us > 2 * afl->queue_cur->exec_us)) { + + ranges = add_range(ranges, rng->start, rng->start + s / 2); + ranges = add_range(ranges, rng->start + s / 2 + 1, rng->end); + memcpy(buf + rng->start, backup, s); + + } else { + + needs_write = 1; + + } + + } - empty_range: ck_free(rng); rng = NULL; ++afl->stage_cur; @@ -196,6 +203,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u32 exec_cksum) { return 0; checksum_fail: + if (rng) ck_free(rng); ck_free(backup); while (ranges) { @@ -242,11 +250,11 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 *buf_64 = (u64 *)&buf[idx]; u32 *buf_32 = (u32 *)&buf[idx]; u16 *buf_16 = (u16 *)&buf[idx]; - u8* buf_8 = &buf[idx]; + u8 * buf_8 = &buf[idx]; u64 *o_buf_64 = (u64 *)&orig_buf[idx]; u32 *o_buf_32 = (u32 *)&orig_buf[idx]; u16 *o_buf_16 = (u16 *)&orig_buf[idx]; - u8* o_buf_8 = &orig_buf[idx]; + u8 * o_buf_8 = &orig_buf[idx]; u32 its_len = len - idx; *status = 0; diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index d42df2db..d48dd5e3 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -387,9 +387,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) { @@ -471,9 +471,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 @@ -503,9 +503,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); @@ -579,7 +579,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"); -- cgit 1.4.1 From 48f7f7a17b8ac848e261cfc47800e1e6d7a51bcb Mon Sep 17 00:00:00 2001 From: Rick van Schijndel Date: Wed, 15 Apr 2020 12:08:33 +0200 Subject: afl-clang-fast: fail when binary name can't be used to determine build mode (#318) --- llvm_mode/afl-clang-fast.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 49318f2e..f58c22dd 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -184,7 +184,7 @@ static void edit_params(u32 argc, char **argv, char **envp) { sprintf(llvm_fullpath, CLANGPP_BIN); cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; - } else { + } else if (!strcmp(name, "afl-clang-fast") || !strcmp(name, "afl-clang-lto")) { u8 *alt_cc = getenv("AFL_CC"); if (USE_BINDIR) @@ -193,6 +193,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { sprintf(llvm_fullpath, CLANG_BIN); cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath; + } else { + fprintf(stderr, "Name of the binary: %s\n", argv[0]); + FATAL("Name of the binary is not a known name, expected afl-clang-fast(++) or afl-clang-lto(++)"); } /* There are three ways to compile with afl-clang-fast. In the traditional -- cgit 1.4.1 From 0c02a8f4d31480c8459bc695ae655b69d02b98df Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Wed, 15 Apr 2020 19:23:26 +0200 Subject: changed run_target --- include/afl-fuzz.h | 4 ++-- include/forkserver.h | 10 +++++---- llvm_mode/afl-clang-fast.c | 10 +++++++-- src/afl-forkserver.c | 13 +++++++----- src/afl-fuzz-bitmap.c | 12 +++++++---- src/afl-fuzz-run.c | 10 +-------- src/afl-showmap.c | 18 ++++++++-------- src/afl-tmin.c | 51 +++++++++++++++++++++++----------------------- 8 files changed, 68 insertions(+), 60 deletions(-) (limited to 'llvm_mode') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 38501699..7c6019e6 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -842,10 +842,10 @@ u32 count_bytes(afl_state_t *, u8 *); u32 count_non_255_bytes(afl_state_t *, u8 *); #ifdef WORD_SIZE_64 void simplify_trace(afl_state_t *, u64 *); -void classify_counts(afl_state_t *, u64 *); +void classify_counts(afl_forkserver_t *); #else void simplify_trace(afl_state_t *, u32 *); -void classify_counts(afl_state_t *, u32 *); +void classify_counts(afl_forkserver_t *); #endif void init_count_class16(void); void minimize_bits(afl_state_t *, u8 *, u8 *); diff --git a/include/forkserver.h b/include/forkserver.h index 82953855..f24393bc 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -97,10 +97,12 @@ void afl_fsrv_init(afl_forkserver_t *fsrv); void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from); void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output); -fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, - volatile u8 * stop_soon_p); -void afl_fsrv_killall(void); -void afl_fsrv_deinit(afl_forkserver_t *fsrv); +fsrv_run_result_t afl_fsrv_run_target( + afl_forkserver_t *fsrv, u32 timeout, + void(classify_counts_func)(afl_forkserver_t *fsrv), + volatile u8 *stop_soon_p); +void afl_fsrv_killall(void); +void afl_fsrv_deinit(afl_forkserver_t *fsrv); #ifdef __APPLE__ #define MSG_FORK_ON_APPLE \ diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index f58c22dd..57d7b89a 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -184,7 +184,9 @@ static void edit_params(u32 argc, char **argv, char **envp) { sprintf(llvm_fullpath, CLANGPP_BIN); cc_params[0] = alt_cxx && *alt_cxx ? alt_cxx : (u8 *)llvm_fullpath; - } else if (!strcmp(name, "afl-clang-fast") || !strcmp(name, "afl-clang-lto")) { + } else if (!strcmp(name, "afl-clang-fast") || + + !strcmp(name, "afl-clang-lto")) { u8 *alt_cc = getenv("AFL_CC"); if (USE_BINDIR) @@ -194,8 +196,12 @@ static void edit_params(u32 argc, char **argv, char **envp) { cc_params[0] = alt_cc && *alt_cc ? alt_cc : (u8 *)llvm_fullpath; } else { + fprintf(stderr, "Name of the binary: %s\n", argv[0]); - FATAL("Name of the binary is not a known name, expected afl-clang-fast(++) or afl-clang-lto(++)"); + FATAL( + "Name of the binary is not a known name, expected afl-clang-fast(++) " + "or afl-clang-lto(++)"); + } /* There are three ways to compile with afl-clang-fast. In the traditional diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index f0040617..89480b07 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -643,16 +643,16 @@ static void afl_fsrv_kill(afl_forkserver_t *fsrv) { /* Execute target application, monitoring for timeouts. Return status information. The called program will update afl->fsrv->trace_bits. */ -fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, - volatile u8 * stop_soon_p) { +fsrv_run_result_t afl_fsrv_run_target( + afl_forkserver_t *fsrv, u32 timeout, + void(classify_counts_func)(afl_forkserver_t *fsrv), + volatile u8 *stop_soon_p) { s32 res; u32 exec_ms; int status = 0; - u32 timeout = fsrv->exec_tmout; - /* After this memset, fsrv->trace_bits[] are effectively volatile, so we must prevent any earlier operations from venturing into that territory. */ @@ -732,6 +732,9 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, behave very normally and do not have to be treated as volatile. */ MEM_BARRIER(); + u32 tb4 = *(u32 *)fsrv->trace_bits; + + if (likely(classify_counts_func)) classify_counts_func(fsrv); /* Report outcome to caller. */ @@ -756,7 +759,7 @@ fsrv_run_result_t afl_fsrv_run_target(afl_forkserver_t *fsrv, } - if ((*(u32 *)fsrv->trace_bits) == EXEC_FAIL_SIG) return FSRV_RUN_NOINST; + if (tb4 == EXEC_FAIL_SIG) return FSRV_RUN_ERROR; return FSRV_RUN_OK; diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 298a6207..c5cede4d 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -351,9 +351,11 @@ void init_count_class16(void) { #ifdef WORD_SIZE_64 -void classify_counts(afl_state_t *afl, u64 *mem) { +void classify_counts(afl_forkserver_t *fsrv) { - u32 i = (afl->fsrv.map_size >> 3); + u32 *mem = (u32 *)fsrv->trace_bits; + + u32 i = (fsrv->map_size >> 3); if (i == 0) i = 1; @@ -380,9 +382,11 @@ void classify_counts(afl_state_t *afl, u64 *mem) { #else -void classify_counts(afl_state_t *afl, u32 *mem) { +void classify_counts(afl_forkserver_t *fsrv) { - u32 i = (afl->fsrv.map_size >> 2); + u64 *mem = (u64 *)fsrv->trace_bits; + + u32 i = (fsrv->map_size >> 2); if (i == 0) i = 1; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 370a7734..c3ed59ef 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -35,15 +35,7 @@ fsrv_run_result_t run_target(afl_state_t *afl, afl_forkserver_t *fsrv, u32 timeout) { - fsrv_run_result_t res = afl_fsrv_run_target(&afl->fsrv, &afl->stop_soon); - -#ifdef WORD_SIZE_64 - classify_counts(afl, (u64 *)fsrv->trace_bits); -#else - classify_counts(afl, (u32 *)fsrv->trace_bits); -#endif /* ^WORD_SIZE_64 */ - - return res; + return afl_fsrv_run_target(fsrv, timeout, classify_counts, &afl->stop_soon); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index fa799bf9..2326d469 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -106,7 +106,10 @@ static const u8 count_class_binary[256] = { }; -static void classify_counts(u8 *mem, const u8 *map) { +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; @@ -240,12 +243,12 @@ void run_target_forkserver(afl_forkserver_t *fsrv, char **argv, u8 *mem, write_to_testcase(fsrv, mem, len); - fsrv_run_result_t res = afl_fsrv_run_target(fsrv, &stop_soon); - if (res == FSRV_RUN_NOINST || res == FSRV_RUN_ERROR) + if (afl_fsrv_run_target(fsrv, fsrv->exec_tmout, classify_counts, + &stop_soon) == FSRV_RUN_ERROR) { + FATAL("Error running target"); - classify_counts(fsrv->trace_bits, - binary_mode ? count_class_binary : count_class_human); + } if (stop_soon) { @@ -375,8 +378,7 @@ static void run_target(afl_forkserver_t *fsrv, char **argv) { if (*(u32 *)fsrv->trace_bits == EXEC_FAIL_SIG) FATAL("Unable to execute '%s'", argv[0]); - classify_counts(fsrv->trace_bits, - binary_mode ? count_class_binary : count_class_human); + classify_counts(fsrv); if (!quiet_mode) SAYF(cRST "-- Program output ends --\n"); @@ -587,7 +589,7 @@ static void find_binary(afl_forkserver_t *fsrv, u8 *fname) { break; ck_free(fsrv->target_path); - fsrv->target_path = 0; + fsrv->target_path = NULL; } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index c994c2de..84e9a498 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -100,8 +100,29 @@ static const u8 count_class_lookup[256] = { }; -static void classify_counts(u8 *mem) { +/* Apply mask to classified bitmap (if set). */ + +static void apply_mask(u32 *mem, u32 *mask) { + + u32 i = (MAP_SIZE >> 2); + + if (!mask) return; + + while (i--) { + + *mem &= ~*mask; + mem++; + mask++; + + } +} + +static void classify_counts(afl_forkserver_t *fsrv) { + + if (hang_mode) return; /* We only want hangs */ + + u8 *mem = fsrv->trace_bits; u32 i = MAP_SIZE; if (edges_only) { @@ -124,23 +145,7 @@ static void classify_counts(u8 *mem) { } -} - -/* Apply mask to classified bitmap (if set). */ - -static void apply_mask(u32 *mem, u32 *mask) { - - u32 i = (MAP_SIZE >> 2); - - if (!mask) return; - - while (i--) { - - *mem &= ~*mask; - mem++; - mask++; - - } + apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap); } @@ -250,17 +255,11 @@ static u8 run_target(afl_forkserver_t *fsrv, char **argv, u8 *mem, u32 len, write_to_testcase(fsrv, mem, len); - fsrv_run_result_t ret = afl_fsrv_run_target(fsrv, &stop_soon); + fsrv_run_result_t ret = + afl_fsrv_run_target(fsrv, fsrv->exec_tmout, classify_counts, &stop_soon); if (ret == FSRV_RUN_ERROR) FATAL("Couldn't run child"); - if (!hang_mode) { - - classify_counts(fsrv->trace_bits); - apply_mask((u32 *)fsrv->trace_bits, (u32 *)mask_bitmap); - - } - if (stop_soon) { SAYF(cRST cLRD "\n+++ Minimization aborted by user +++\n" cRST); -- cgit 1.4.1 From 7e2c52f2b90c544981341248a13b64174b889b7a Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Wed, 15 Apr 2020 22:27:32 +0200 Subject: disable compare-transform-pass when lto_mode and autodictionary is used. --- llvm_mode/README.lto.md | 16 ++++++++-------- llvm_mode/afl-clang-fast.c | 6 ++++-- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 51b50544..9af9ffff 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -17,17 +17,17 @@ This version requires a current llvm 11 compiled from the github master. ## Introduction and problem description A big issue with how afl/afl++ works is that the basic block IDs that are -set during compilation are random - and hence natually the larger the number -of instrumented locations, the higher the number of edge collisions in the +set during compilation are random - and hence naturally the larger the number +of instrumented locations, the higher the number of edge collisions are in the map. This can result in not discovering new paths and therefore degrade the -efficiency of the fuzzing. +efficiency of the fuzzing process. -*This issue is understimated in the fuzzing community!* +*This issue is underestimated in the fuzzing community!* With a 2^16 = 64kb standard map at already 256 instrumented blocks there is on average one collision. On average a target has 10.000 to 50.000 instrumented blocks hence the real collisions are between 750-18.000! -To get to a solution that prevents any collision took several approaches +To reach a solution that prevents any collisions took several approaches and many dead ends until we got to this: * We instrument at link time when we have all files pre-compiled @@ -76,7 +76,7 @@ $ make install ## How to use afl-clang-lto -Just use afl-clang-lto like you did afl-clang-fast or afl-gcc. +Just use afl-clang-lto like you did with afl-clang-fast or afl-gcc. Also whitelisting (AFL_LLVM_WHITELIST -> [README.whitelist.md](README.whitelist.md)) and laf-intel/compcov (AFL_LLVM_LAF_* -> [README.laf-intel.md](README.laf-intel.md)) work. @@ -120,7 +120,7 @@ Please report issues at: ## Upcoming Work -1. Currently the LTO whitelist feature does not allow to not instrument main, +1. Currently the LTO whitelist feature does not allow to instrument main, start and init functions ## History @@ -138,7 +138,7 @@ This was first implemented in January and work ... kinda. The LTO time instrumentation worked, however the "how" the basic blocks were instrumented was a problem, as reducing duplicates turned out to be very, very difficult with a program that has so many paths and therefore so many -dependencies. At lot of stratgies were implemented - and failed. +dependencies. At lot of strategies 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. diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 57d7b89a..082e307a 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -223,8 +223,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (getenv("LAF_TRANSFORM_COMPARES") || - getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { + if (!getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary + && instrument_mode != INSTRUMENT_LTO // and lto_mode is used + && (getenv("LAF_TRANSFORM_COMPARES") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; -- cgit 1.4.1 From 2ce6e7a7fb5aedf058dc549e57610cee166508d2 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Wed, 15 Apr 2020 23:01:33 +0200 Subject: fix laf-intel transform disable --- llvm_mode/afl-clang-fast.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 082e307a..84ebeb9a 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -223,8 +223,8 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if (!getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary - && instrument_mode != INSTRUMENT_LTO // and lto_mode is used + if ((!(getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary + && instrument_mode != INSTRUMENT_LTO)) // and lto_mode is used && (getenv("LAF_TRANSFORM_COMPARES") || getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { -- cgit 1.4.1 From 124665b392aa081807c8fa19948937a07de6053b Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 16 Apr 2020 14:47:08 +0200 Subject: code-format --- llvm_mode/afl-clang-fast.c | 8 ++++---- src/afl-forkserver.c | 7 +++++-- src/afl-fuzz-bitmap.c | 14 ++++++++------ src/afl-fuzz-run.c | 2 +- src/afl-showmap.c | 8 ++------ src/afl-tmin.c | 3 +-- 6 files changed, 21 insertions(+), 21 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 84ebeb9a..c0471033 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -223,10 +223,10 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if ((!(getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary - && instrument_mode != INSTRUMENT_LTO)) // and lto_mode is used - && (getenv("LAF_TRANSFORM_COMPARES") || - getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { + if ((!(getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary + && instrument_mode != INSTRUMENT_LTO)) // and lto_mode is used + && (getenv("LAF_TRANSFORM_COMPARES") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { cc_params[cc_par_cnt++] = "-Xclang"; cc_params[cc_par_cnt++] = "-load"; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 5727c7f2..5cd000d7 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -408,11 +408,14 @@ 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)) { + if (unlikely(fsrv->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); + } + if (!be_quiet) ACTF("Target map size: %u", fsrv->map_size); if (fsrv->map_size > MAP_SIZE) FATAL( @@ -787,7 +790,7 @@ fsrv_run_result_t afl_fsrv_run_target( behave very normally and do not have to be treated as volatile. */ MEM_BARRIER(); - //u32 tb4 = *(u32 *)fsrv->trace_bits; + // u32 tb4 = *(u32 *)fsrv->trace_bits; if (likely(classify_counts_func)) classify_counts_func(fsrv); diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 7be44fd5..92966c8c 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -112,18 +112,20 @@ u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { #ifdef WORD_SIZE_64 - if (*virgin == 0xffffffffffffffff || (cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || - (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff) || - (cur[4] && vir[4] == 0xff) || (cur[5] && vir[5] == 0xff) || - (cur[6] && vir[6] == 0xff) || (cur[7] && vir[7] == 0xff)) + if (*virgin == 0xffffffffffffffff || (cur[0] && vir[0] == 0xff) || + (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) || + (cur[3] && vir[3] == 0xff) || (cur[4] && vir[4] == 0xff) || + (cur[5] && vir[5] == 0xff) || (cur[6] && vir[6] == 0xff) || + (cur[7] && vir[7] == 0xff)) ret = 2; else ret = 1; #else - if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) || (cur[1] && vir[1] == 0xff) || - (cur[2] && vir[2] == 0xff) || (cur[3] && vir[3] == 0xff)) + if (*virgin == 0xffffffff || (cur[0] && vir[0] == 0xff) || + (cur[1] && vir[1] == 0xff) || (cur[2] && vir[2] == 0xff) || + (cur[3] && vir[3] == 0xff)) ret = 2; else ret = 1; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 4aec01f0..3933acd8 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -50,7 +50,7 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { s32 doc_fd; char fn[PATH_MAX]; snprintf(fn, PATH_MAX, "%s/mutations/%09u:%s", afl->out_dir, - afl->document_counter++, describe_op(afl, 0)); + afl->document_counter++, describe_op(afl, 0)); if ((doc_fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0600)) >= 0) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 2a4ab96e..48436c34 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -63,8 +63,7 @@ static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ - *out_file = NULL, - *at_file = NULL; /* Substitution string for @@ */ + *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ static u8 *in_data; /* Input data */ @@ -878,8 +877,7 @@ int main(int argc, char **argv_orig, char **envp) { if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; #endif - snprintf(outfile, sizeof(outfile), "%s/%s", out_file, - dir_ent->d_name); + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); if (read_file(infile)) { @@ -901,8 +899,6 @@ int main(int argc, char **argv_orig, char **envp) { run_target(fsrv, use_argv); tcnt = write_results_to_file(fsrv, out_file); - - } if (!quiet_mode) { diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 78ed63e2..cb53f56f 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -62,8 +62,7 @@ static u8 *mask_bitmap; /* Mask for trace bits (-B) */ static u8 *in_file, /* Minimizer input test case */ - *out_file, - *output_file; /* Minimizer output file */ + *out_file, *output_file; /* Minimizer output file */ static u8 *in_data; /* Input data for trimming */ -- 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 'llvm_mode') 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 248a2f2f0bfddd9f79a4c6b6ceadef32f1765969 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 10:21:41 +0200 Subject: added AFL_MAP_SIZE to env help output --- llvm_mode/afl-clang-fast.c | 50 +++++++++++++++++++++++----------------------- src/afl-analyze.c | 4 +++- src/afl-fuzz.c | 50 ++++++++++++++++++++++++---------------------- src/afl-showmap.c | 11 ++++++---- src/afl-tmin.c | 4 +++- 5 files changed, 64 insertions(+), 55 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 5abe61c6..7466db26 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -716,30 +716,30 @@ int main(int argc, char **argv, char **envp) { "Environment variables used:\n" "AFL_CC: path to the C compiler to use\n" "AFL_CXX: path to the C++ compiler to use\n" - "AFL_PATH: path to instrumenting pass and runtime " - "(afl-llvm-rt.*o)\n" - "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" - "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" - "AFL_INST_RATIO: percentage of branches to instrument\n" - "AFL_QUIET: suppress verbose output\n" "AFL_DEBUG: enable developer debugging output\n" + "AFL_DONT_OPTIMIZE: disable optimization instead of -O3\n" "AFL_HARDEN: adds code hardening to catch memory bugs\n" - "AFL_USE_ASAN: activate address sanitizer\n" - "AFL_USE_MSAN: activate memory sanitizer\n" - "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n" - "AFL_USE_CFISAN: activate control flow sanitizer\n" - "AFL_LLVM_WHITELIST: enable whitelisting (selective " - "instrumentation)\n" + "AFL_INST_RATIO: percentage of branches to instrument\n" "AFL_LLVM_NOT_ZERO: use cycling trace counters that skip zero\n" "AFL_LLVM_LAF_SPLIT_COMPARES: enable cascaded comparisons\n" - "AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n" - "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison " - "function calls\n" - " to cascaded comparisons\n" "AFL_LLVM_LAF_SPLIT_FLOATS: transform floating point comp. to " "cascaded " "comp.\n" - "AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n", + "AFL_LLVM_LAF_SPLIT_SWITCHES: casc. comp. in 'switch'\n" + " to cascaded comparisons\n" + "AFL_LLVM_LAF_TRANSFORM_COMPARES: transform library comparison " + "function calls\n" + "AFL_LLVM_LAF_SPLIT_COMPARES_BITW: size limit (default 8)\n" + "AFL_LLVM_WHITELIST: enable whitelisting (selective " + "instrumentation)\n" + "AFL_NO_BUILTIN: compile for use with libtokencap.so\n" + "AFL_PATH: path to instrumenting pass and runtime " + "(afl-llvm-rt.*o)\n" + "AFL_QUIET: suppress verbose output\n" + "AFL_USE_ASAN: activate address sanitizer\n" + "AFL_USE_CFISAN: activate control flow sanitizer\n" + "AFL_USE_MSAN: activate memory sanitizer\n" + "AFL_USE_UBSAN: activate undefined behaviour sanitizer\n", callname, BIN_PATH, BIN_PATH); SAYF( @@ -747,21 +747,21 @@ int main(int argc, char **argv, char **envp) { "AFL_LLVM_CMPLOG: log operands of comparisons (RedQueen mutator)\n" "AFL_LLVM_INSTRUMENT: set instrumentation mode: DEFAULT, CFG " "(INSTRIM), LTO, CTX, NGRAM-2 ... NGRAM-16\n" - "You can also use the old environment variables:" - "AFL_LLVM_CTX: use context sensitive coverage\n" - "AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" - "AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n" - "AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" - "AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub " + " You can also use the old environment variables instead:" + " AFL_LLVM_CTX: use context sensitive coverage\n" + " AFL_LLVM_USE_TRACE_PC: use LLVM trace-pc-guard instrumentation\n" + " AFL_LLVM_NGRAM_SIZE: use ngram prev_loc count coverage\n" + " AFL_LLVM_INSTRIM: use light weight instrumentation InsTrim\n" + " AFL_LLVM_INSTRIM_LOOPHEAD: optimize loop tracing for speed (sub " "option to INSTRIM)\n"); #ifdef AFL_CLANG_FLTO SAYF( "\nafl-clang-lto specific environment variables:\n" - "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a " - "bb\n" "AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " "global var\n" + "AFL_LLVM_LTO_STARTID: from which ID to start counting from for a " + "bb\n" "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" diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 3d86efb1..8a84b781 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -796,8 +796,10 @@ static void usage(u8 *argv0) { " (must contain abort_on_error=1 and symbolize=0)\n" "MSAN_OPTIONS: custom settings for MSAN\n" " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_ANALYZE_HEX: print file offsets in hexadecimal instead of decimal\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" + " the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_SKIP_BIN_CHECK: skip checking the location of and the target\n" , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3cf57f86..2a1387a9 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -150,44 +150,46 @@ static void usage(afl_state_t *afl, u8 *argv0, int more_help) { if (more_help > 1) SAYF( "Environment variables used:\n" - "AFL_PATH: path to AFL support binaries\n" - "AFL_QUIET: suppress forkserver status messages\n" - "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n" "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n" + "ASAN_OPTIONS: custom settings for ASAN\n" + " (must contain abort_on_error=1 and symbolize=0)\n" + "MSAN_OPTIONS: custom settings for MSAN\n" + " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "AFL_BENCH_JUST_ONE: run the target just once\n" - "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" + "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" "AFL_CUSTOM_MUTATOR_LIBRARY: lib with afl_custom_fuzz() to mutate inputs\n" "AFL_CUSTOM_MUTATOR_ONLY: avoid AFL++'s internal mutators\n" - "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" "AFL_DEBUG: extra debugging output for Python mode trimming\n" + "AFL_DEBUG_CHILD_OUTPUT: do not suppress stdout/stderr from target\n" "AFL_DISABLE_TRIM: disable the trimming of test cases\n" - "AFL_NO_UI: switch status screen off\n" - "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" - "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" - "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" - "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" - "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" - "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" - "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" + "AFL_DUMB_FORKSRV: use fork server without feedback from target\n" + "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" "AFL_FAST_CAL: limit the calibration stage to three cycles for speedup\n" + "AFL_FORCE_UI: force showing the status screen (for virtual consoles)\n" "AFL_HANG_TMOUT: override timeout value (in milliseconds)\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" - "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n" + "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" "AFL_IMPORT_FIRST: sync and import test cases from other fuzzer instances first\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" + " the target was compiled for\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" + "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" + "AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" + "AFL_NO_SNAPSHOT: do not use the snapshot feature (if the snapshot lkm is loaded)\n" + "AFL_NO_UI: switch status screen off\n" + "AFL_PATH: path to AFL support binaries\n" "AFL_POST_LIBRARY: postprocess generated test cases before use as target input\n" - "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" - "AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES: don't warn about core dump handlers\n" - "ASAN_OPTIONS: custom settings for ASAN\n" - " (must contain abort_on_error=1 and symbolize=0)\n" - "MSAN_OPTIONS: custom settings for MSAN\n" - " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" + "AFL_PYTHON_MODULE: mutate and trim inputs with the specified Python module\n" + "AFL_QUIET: suppress forkserver status messages\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_SHUFFLE_QUEUE: reorder the input queue randomly on startup\n" "AFL_SKIP_BIN_CHECK: skip the check, if the target is an excutable\n" + "AFL_SKIP_CPUFREQ: do not warn about variable cpu clocking\n" + "AFL_SKIP_CRASHES: during initial dry run do not terminate for crashing inputs\n" + "AFL_TMPDIR: directory to use for input file generation (ramdisk recommended)\n" //"AFL_PERSISTENT: not supported anymore -> no effect, just a warning\n" //"AFL_DEFER_FORKSRV: not supported anymore -> no effect, just a warning\n" - "AFL_EXIT_WHEN_DONE: exit when all inputs are run and no new finds are found\n" - "AFL_BENCH_UNTIL_CRASH: exit soon when the first crashing input has been found\n" - "AFL_AUTORESUME: resume fuzzing if directory specified by -o already exists\n" "\n" ); else diff --git a/src/afl-showmap.c b/src/afl-showmap.c index c1561b4c..59c76d41 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -515,13 +515,16 @@ static void usage(u8 *argv0) { "For additional help, consult %s/README.md.\n\n" "Environment variables used:\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" - "AFL_DEBUG: enable extra developer output\n" - "AFL_QUIET: do not print extra informational output" + "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n", "AFL_CMIN_CRASHES_ONLY: (cmin_mode) only write tuples for crashing " "inputs\n" "AFL_CMIN_ALLOW_ANY: (cmin_mode) write tuples for crashing inputs also\n" - "LD_BIND_LAZY: do not set LD_BIND_NOW env var for target\n", + "AFL_DEBUG: enable extra developer output\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " + "size\n" + " the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_QUIET: do not print extra informational output" argv0, MEM_LIMIT, doc_path); exit(1); diff --git a/src/afl-tmin.c b/src/afl-tmin.c index e366d260..ad7d70c7 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -741,7 +741,9 @@ static void usage(u8 *argv0) { " (must contain abort_on_error=1 and symbolize=0)\n" "MSAN_OPTIONS: custom settings for MSAN\n" " (must contain exitcode="STRINGIFY(MSAN_ERROR)" and symbolize=0)\n" - "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_MAP_SIZE: the shared memory size for that target. must be >= the size\n" + " the target was compiled for\n" + "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" "AFL_TMIN_EXACT: require execution paths to match for crashing inputs\n" , argv0, EXEC_TIMEOUT, MEM_LIMIT, doc_path); -- cgit 1.4.1 From 2162fd8e1a1ceb745c1fcf87fb6a1053508591c4 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 10:46:35 +0200 Subject: preliminary stuff for AFL_MAP_SIZE and afl-llvm-pass --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 2 +- llvm_mode/afl-llvm-pass.so.cc | 68 +++++++++++++++++++++++++++- src/afl-showmap.c | 4 +- 3 files changed, 69 insertions(+), 5 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index a5058974..ece3201f 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -637,7 +637,7 @@ bool AFLLTOPass::runOnModule(Module &M) { if (!f) { fprintf(stderr, - "Error: init function could not be found (this hould not " + "Error: init function could not be found (this should not " "happen)\n"); exit(-1); diff --git a/llvm_mode/afl-llvm-pass.so.cc b/llvm_mode/afl-llvm-pass.so.cc index b4249802..71abcd05 100644 --- a/llvm_mode/afl-llvm-pass.so.cc +++ b/llvm_mode/afl-llvm-pass.so.cc @@ -125,6 +125,7 @@ class AFLCoverage : public ModulePass { std::list myWhitelist; uint32_t ngram_size = 0; uint32_t debug = 0; + uint32_t map_size = MAP_SIZE; char * ctx_str = NULL; }; @@ -192,6 +193,19 @@ bool AFLCoverage::runOnModule(Module &M) { be_quiet = 1; + /* + char *ptr; + 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); + + } + + */ + /* Decide instrumentation ratio */ char * inst_ratio_str = getenv("AFL_INST_RATIO"); @@ -365,7 +379,7 @@ bool AFLCoverage::runOnModule(Module &M) { // if yes we store a context ID for this function in the global var if (has_calls) { - ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(MAP_SIZE)); + ConstantInt *NewCtx = ConstantInt::get(Int32Ty, AFL_R(map_size)); StoreInst * StoreCtx = IRB.CreateStore(NewCtx, AFLContext); StoreCtx->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); @@ -509,7 +523,7 @@ bool AFLCoverage::runOnModule(Module &M) { /* Make up cur_loc */ // cur_loc++; - cur_loc = AFL_R(MAP_SIZE); + cur_loc = AFL_R(map_size); /* There is a problem with Ubuntu 18.04 and llvm 6.0 (see issue #63). The inline function successors() is not inlined and also not found at runtime @@ -705,6 +719,56 @@ bool AFLCoverage::runOnModule(Module &M) { } + /* + // This is currently disabled because we not only need to create/insert a + // function (easy), but also add it as a constructor with an ID < 5 + + if (getenv("AFL_LLVM_DONTWRITEID") == NULL) { + + // 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.o + + Function *f = ... + + if (!f) { + + fprintf(stderr, + "Error: init function could not be created (this should not + happen)\n"); exit(-1); + + } + + ... constructor for f = 4 + + 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 (map_size <= 0x800000) { + + GlobalVariable *AFLFinalLoc = new GlobalVariable( + M, Int32Ty, true, GlobalValue::ExternalLinkage, 0, + "__afl_final_loc", 0, GlobalVariable::GeneralDynamicTLSModel, 0, + false); + ConstantInt *const_loc = ConstantInt::get(Int32Ty, map_size); + StoreInst * StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc); + StoreFinalLoc->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + + } + + } + + */ + /* Say something nice. */ if (!be_quiet) { diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 59c76d41..a11c128a 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -524,8 +524,8 @@ static void usage(u8 *argv0) { "size\n" " the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" - "AFL_QUIET: do not print extra informational output" - argv0, MEM_LIMIT, doc_path); + "AFL_QUIET: do not print extra informational output" argv0, + MEM_LIMIT, doc_path); exit(1); -- cgit 1.4.1 From 1931838a112a23567b41ac0f018ae811ef7fbe1c Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 11:39:38 +0200 Subject: remove unnecessary map_size variables --- include/afl-fuzz.h | 2 -- include/sharedmem.h | 3 +-- llvm_mode/afl-clang-fast.c | 22 ++++++++++++---------- src/afl-fuzz-state.c | 2 +- src/afl-fuzz.c | 2 +- src/afl-sharedmem.c | 4 ++-- 6 files changed, 17 insertions(+), 18 deletions(-) (limited to 'llvm_mode') diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index beef3d58..f6912aea 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -325,8 +325,6 @@ 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/sharedmem.h b/include/sharedmem.h index 57ab6cf0..6aef4b84 100644 --- a/include/sharedmem.h +++ b/include/sharedmem.h @@ -44,8 +44,7 @@ typedef struct sharedmem { u8 *map; /* shared memory region */ - size_t size_alloc; /* actual allocated size */ - size_t size_used; /* in use by shmem app */ + size_t map_size; /* actual allocated size */ int cmplog_mode; struct cmp_map *cmp_map; diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 7466db26..6584b11f 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -223,18 +223,20 @@ static void edit_params(u32 argc, char **argv, char **envp) { } - if ((!(getenv("AFL_LLVM_LTO_AUTODICTIONARY") // disabled when autodictionary - && instrument_mode != INSTRUMENT_LTO)) // and lto_mode is used - && (getenv("LAF_TRANSFORM_COMPARES") || - getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { + if (getenv("LAF_TRANSFORM_COMPARES") || + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/compare-transform-pass.so", obj_path); + if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && + instrument_mode != INSTRUMENT_LTO)) + WARNF("using AFL_LLVM_LAF_TRANSFORM_COMPARES together with AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only AFL_LLVM_LTO_AUTODICTIONARY."); - } + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/compare-transform-pass.so", obj_path); + + } if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 86dafb3e..72bdd91e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -81,7 +81,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { and out_size are NULL/0 by default. */ memset(afl, 0, sizeof(afl_state_t)); - if (!map_size) map_size = MAP_SIZE; + if (!map_size) afl->shm.map_size = MAP_SIZE; afl->w_init = 0.9; afl->w_end = 0.3; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 93e83eed..03726eb0 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -264,7 +264,7 @@ int main(int argc, char **argv_orig, char **envp) { afl_fsrv_init(&afl->fsrv); read_afl_environment(afl, envp); - if (afl->afl_env.map_size) afl->fsrv.map_size = afl->afl_env.map_size; + if (afl->shm.map_size) afl->fsrv.map_size = afl->shm.map_size; exit_1 = !!afl->afl_env.afl_bench_just_one; SAYF(cCYA "afl-fuzz" VERSION cRST diff --git a/src/afl-sharedmem.c b/src/afl-sharedmem.c index 01ba62aa..a130411e 100644 --- a/src/afl-sharedmem.c +++ b/src/afl-sharedmem.c @@ -72,7 +72,7 @@ void afl_shm_deinit(sharedmem_t *shm) { #ifdef USEMMAP if (shm->map != NULL) { - munmap(shm->map, shm->size_alloc); + munmap(shm->map, shm->map_size); shm->map = NULL; } @@ -99,7 +99,7 @@ void afl_shm_deinit(sharedmem_t *shm) { u8 *afl_shm_init(sharedmem_t *shm, size_t map_size, unsigned char dumb_mode) { - shm->size_alloc = shm->size_used = map_size; + shm->map_size = map_size; shm->map = NULL; -- cgit 1.4.1 From d3254d8066ca6cb7d13f4682eb756dc9cf591f32 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Fri, 17 Apr 2020 12:00:28 +0200 Subject: llvm fix --- llvm_mode/afl-clang-fast.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c index 6584b11f..3de5fd7d 100644 --- a/llvm_mode/afl-clang-fast.c +++ b/llvm_mode/afl-clang-fast.c @@ -224,19 +224,22 @@ static void edit_params(u32 argc, char **argv, char **envp) { } if (getenv("LAF_TRANSFORM_COMPARES") || - getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES"))) { + getenv("AFL_LLVM_LAF_TRANSFORM_COMPARES")) { - if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && - instrument_mode != INSTRUMENT_LTO)) - WARNF("using AFL_LLVM_LAF_TRANSFORM_COMPARES together with AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only AFL_LLVM_LTO_AUTODICTIONARY."); + if (!be_quiet && getenv("AFL_LLVM_LTO_AUTODICTIONARY") && + instrument_mode != INSTRUMENT_LTO) + WARNF( + "using AFL_LLVM_LAF_TRANSFORM_COMPARES together with " + "AFL_LLVM_LTO_AUTODICTIONARY makes no sense. Use only " + "AFL_LLVM_LTO_AUTODICTIONARY."); - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = "-load"; - cc_params[cc_par_cnt++] = "-Xclang"; - cc_params[cc_par_cnt++] = - alloc_printf("%s/compare-transform-pass.so", obj_path); + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = "-load"; + cc_params[cc_par_cnt++] = "-Xclang"; + cc_params[cc_par_cnt++] = + alloc_printf("%s/compare-transform-pass.so", obj_path); - } + } if (getenv("LAF_SPLIT_COMPARES") || getenv("AFL_LLVM_LAF_SPLIT_COMPARES")) { -- cgit 1.4.1