diff options
author | van Hauser <vh@thc.org> | 2020-08-11 03:40:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-11 03:40:12 +0200 |
commit | 67dac152269c48245dca88140b1238b36d5e0954 (patch) | |
tree | 81e8f262c1dc403e34c7b287ba68c81bb37cb4d0 | |
parent | 9cf8637fab8cf3fe8aba5660015bbe7177805807 (diff) | |
parent | 50e76fce123f01ec83024f3bbd3190f2e1a6d387 (diff) | |
download | afl++-67dac152269c48245dca88140b1238b36d5e0954.tar.gz |
Merge branch 'debug' into taint
-rw-r--r-- | GNUmakefile | 3 | ||||
-rw-r--r-- | README.md | 18 | ||||
-rw-r--r-- | docs/Changelog.md | 3 | ||||
-rw-r--r-- | include/afl-fuzz.h | 1 | ||||
-rw-r--r-- | include/debug.h | 63 | ||||
-rw-r--r-- | llvm_mode/README.lto.md | 20 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-lto-instrumentation.so.cc | 111 | ||||
-rw-r--r-- | llvm_mode/afl-llvm-rt.o.c | 23 | ||||
-rw-r--r-- | src/afl-forkserver.c | 13 | ||||
-rw-r--r-- | src/afl-fuzz-cmplog.c | 4 | ||||
-rw-r--r-- | src/afl-fuzz-mutators.c | 1 | ||||
-rw-r--r-- | src/afl-fuzz-one.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz-run.c | 2 | ||||
-rw-r--r-- | src/afl-fuzz.c | 5 | ||||
-rwxr-xr-x | test/test-basic.sh | 2 |
15 files changed, 187 insertions, 84 deletions
diff --git a/GNUmakefile b/GNUmakefile index 4d0c434e..027ebfd9 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -98,7 +98,7 @@ ifneq "$(shell uname -m)" "x86_64" endif CFLAGS ?= -O3 -funroll-loops $(CFLAGS_OPT) -override CFLAGS += -g -Wno-pointer-sign \ +override CFLAGS += -g -Wno-pointer-sign -Wno-variadic-macros -Wall -Wextra -Wpointer-arith \ -I include/ -DAFL_PATH=\"$(HELPER_PATH)\" \ -DBIN_PATH=\"$(BIN_PATH)\" -DDOC_PATH=\"$(DOC_PATH)\" @@ -198,6 +198,7 @@ else endif ifneq "$(filter Linux GNU%,$(shell uname))" "" + override CFLAGS += -D_FORTIFY_SOURCE=2 LDFLAGS += -ldl -lrt endif diff --git a/README.md b/README.md index d2dc4a95..2b9bc588 100644 --- a/README.md +++ b/README.md @@ -71,18 +71,18 @@ only new bytes in the other cycle. Android support and much, much, much more. | Feature/Instrumentation | afl-gcc | llvm_mode | gcc_plugin | qemu_mode | unicorn_mode | - | ------------------------ |:-------:|:---------:|:----------:|:----------------:|:------------:| - | NeverZero | x | x(1) | (2) | x | x | - | Persistent mode | | x | x | x86[_64]/arm[64] | x | + | -------------------------|:-------:|:---------:|:----------:|:----------------:|:------------:| + | NeverZero | x86[_64]| x(1) | (2) | x | x | + | Persistent Mode | | x | x | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | x86[_64]/arm[64] | x86[_64]/arm | | CmpLog | | x | | x86[_64]/arm[64] | | - | Selective instrumentation| | x | x | (x)(3) | | - | Non-colliding coverage | | x(4) | | (x)(5) | | + | Selective Instrumentation| | x | x | (x)(3) | | + | Non-Colliding Coverage | | x(4) | | (x)(5) | | | InsTrim | | x | | | | - | Ngram prev_loc coverage | | x(6) | | | | - | Context coverage | | x | | | | - | Auto dictionary | | x(7) | | | | - | Snapshot LKM support | | x | | (x)(5) | | + | Ngram prev_loc Coverage | | x(6) | | | | + | Context Coverage | | x | | | | + | Auto Dictionary | | x(7) | | | | + | Snapshot LKM Support | | x | | (x)(5) | | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in llvm <= 8 2. GCC creates non-performant code, hence it is disabled in gcc_plugin diff --git a/docs/Changelog.md b/docs/Changelog.md index f8742b1c..25c7a761 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -28,6 +28,9 @@ sending a mail to <afl-users+subscribe@googlegroups.com>. sancov, and also supports function matching! - fixes for laf-intel float splitting (thanks to mark-griffin for reporting) + - LTO: switch default to the dynamic memory map, set AFL_LLVM_MAP_ADDR + for a fixed map address (eg. 0x10000) + - LTO: skipping ctors and ifuncs in fix map address instrumentation - LTO: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 88392867..02c36861 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -670,6 +670,7 @@ typedef struct afl_state { struct custom_mutator { const char *name; + char * name_short; void * dh; u8 * post_process_buf; size_t post_process_size; diff --git a/include/debug.h b/include/debug.h index ae2946f0..f9ebce58 100644 --- a/include/debug.h +++ b/include/debug.h @@ -28,11 +28,6 @@ #include "types.h" #include "config.h" -/* __FUNCTION__ is non-iso */ -#ifdef __func__ - #define __FUNCTION__ __func__ -#endif - /******************* * Terminal colors * *******************/ @@ -223,43 +218,43 @@ /* Die with a verbose non-OS fatal error message. */ -#define FATAL(x...) \ - do { \ - \ - SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ - "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \ - __FILE__, __LINE__); \ - exit(1); \ - \ +#define FATAL(x...) \ + do { \ + \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ + "\n[-] PROGRAM ABORT : " cRST x); \ + SAYF(cLRD "\n Location : " cRST "%s(), %s:%u\n\n", __func__, \ + __FILE__, __LINE__); \ + exit(1); \ + \ } while (0) /* Die by calling abort() to provide a core dump. */ -#define ABORT(x...) \ - do { \ - \ - SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ - "\n[-] PROGRAM ABORT : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __FUNCTION__, \ - __FILE__, __LINE__); \ - abort(); \ - \ +#define ABORT(x...) \ + do { \ + \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ + "\n[-] PROGRAM ABORT : " cRST x); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n\n", __func__, \ + __FILE__, __LINE__); \ + abort(); \ + \ } while (0) /* Die while also including the output of perror(). */ -#define PFATAL(x...) \ - do { \ - \ - fflush(stdout); \ - SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ - "\n[-] SYSTEM ERROR : " cRST x); \ - SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __FUNCTION__, \ - __FILE__, __LINE__); \ - SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ - exit(1); \ - \ +#define PFATAL(x...) \ + do { \ + \ + fflush(stdout); \ + SAYF(bSTOP RESET_G1 CURSOR_SHOW cRST cLRD \ + "\n[-] SYSTEM ERROR : " cRST x); \ + SAYF(cLRD "\n Stop location : " cRST "%s(), %s:%u\n", __func__, \ + __FILE__, __LINE__); \ + SAYF(cLRD " OS message : " cRST "%s\n", strerror(errno)); \ + exit(1); \ + \ } while (0) /* Die with FATAL() or PFATAL() depending on the value of res (used to diff --git a/llvm_mode/README.lto.md b/llvm_mode/README.lto.md index 4d643324..9046c5a8 100644 --- a/llvm_mode/README.lto.md +++ b/llvm_mode/README.lto.md @@ -17,9 +17,6 @@ This version requires a current llvm 11+ compiled from the github master. 5. If any problems arise be sure to set `AR=llvm-ar RANLIB=llvm-ranlib`. Some targets might need `LD=afl-clang-lto` and others `LD=afl-ld-lto`. -6. If a target uses _init functions or early constructors then additionally - set `AFL_LLVM_MAP_DYNAMIC=1` as your target will crash otherwise! - ## Introduction and problem description A big issue with how afl/afl++ works is that the basic block IDs that are @@ -128,14 +125,14 @@ on start. This improves coverage statistically by 5-10% :) ## Fixed memory map -To speed up fuzzing, the shared memory map is hard set to a specific address, -by default 0x10000. In most cases this will work without any problems. +To speed up fuzzing, it is possible to set a fixed shared memory map. +Recommened is the value 0x10000. +In most cases this will work without any problems. However if a target uses +early constructors, ifuncs or a deferred forkserver this can crash the target. On unusual operating systems/processors/kernels or weird libraries this might fail so to change the fixed address at compile time set AFL_LLVM_MAP_ADDR with a better value (a value of 0 or empty sets the map address to be dynamic - the original afl way, which is slower). -AFL_LLVM_MAP_DYNAMIC can be set so the shared memory address is dynamic (which -is safer but also slower). ## Document edge IDs @@ -262,15 +259,6 @@ If this succeeeds then there is an issue with afl-clang-lto. Please report at Even some targets where clang-12 fails can be build if the fail is just in `./configure`, see `Solving difficult targets` above. -### Target crashes immediately - -If the target is using early constructors (priority values smaller than 6) -or have their own _init/.init functions and these are instrumented then the -target will likely crash when started. This can be avoided by compiling with -`AFL_LLVM_MAP_DYNAMIC=1` . - -This can e.g. happen with OpenSSL. - ## History This was originally envisioned by hexcoder- in Summer 2019, however we saw no diff --git a/llvm_mode/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index 38c3f202..fd8e48a7 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -49,6 +49,7 @@ #include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Pass.h" +#include "llvm/IR/Constants.h" #include "afl-llvm-common.h" @@ -135,7 +136,10 @@ bool AFLLTOPass::runOnModule(Module &M) { if (getenv("AFL_LLVM_LTO_AUTODICTIONARY")) autodictionary = 1; - if (getenv("AFL_LLVM_MAP_DYNAMIC")) map_addr = 0; + // we make this the default as the fixed map has problems with + // defered forkserver, early constructors, ifuncs and maybe more + /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/ + map_addr = 0; if (getenv("AFL_LLVM_SKIPSINGLEBLOCK")) function_minimum_size = 2; @@ -196,7 +200,8 @@ bool AFLLTOPass::runOnModule(Module &M) { ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); - /* This dumps all inialized global strings - might be useful in the future + // This dumps all inialized global strings - might be useful in the future + /* for (auto G=M.getGlobalList().begin(); G!=M.getGlobalList().end(); G++) { GlobalVariable &GV=*G; @@ -212,7 +217,79 @@ bool AFLLTOPass::runOnModule(Module &M) { } - */ + */ + + std::vector<std::string> module_block_list; + + if (map_addr) { + + for (GlobalIFunc &IF : M.ifuncs()) { + + StringRef ifunc_name = IF.getName(); + Constant *r = IF.getResolver(); + StringRef r_name = cast<Function>(r->getOperand(0))->getName(); + if (!be_quiet) + fprintf(stderr, + "Warning: Found an ifunc with name %s that points to resolver " + "function %s, we cannot instrument this, putting it into a " + "block list.\n", + ifunc_name.str().c_str(), r_name.str().c_str()); + module_block_list.push_back(r_name.str()); + + } + + GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors"); + if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) { + + ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); + + if (InitList) { + + for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { + + if (ConstantStruct *CS = + dyn_cast<ConstantStruct>(InitList->getOperand(i))) { + + if (CS->getNumOperands() >= 2) { + + if (CS->getOperand(1)->isNullValue()) + break; // Found a null terminator, stop here. + + ConstantInt *CI = dyn_cast<ConstantInt>(CS->getOperand(0)); + int Priority = CI ? CI->getSExtValue() : 0; + + Constant *FP = CS->getOperand(1); + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) + if (CE->isCast()) FP = CE->getOperand(0); + if (Function *F = dyn_cast<Function>(FP)) { + + if (!F->isDeclaration() && + strncmp(F->getName().str().c_str(), "__afl", 5) != 0 && + Priority <= 5) { + + if (!be_quiet) + fprintf(stderr, + "Warning: Found constructor function %s with prio " + "%u, we cannot instrument this, putting it into a " + "block list.\n", + F->getName().str().c_str(), Priority); + module_block_list.push_back(F->getName().str()); + + } + + } + + } + + } + + } + + } + + } + + } /* Instrument all the things! */ @@ -220,12 +297,36 @@ bool AFLLTOPass::runOnModule(Module &M) { for (auto &F : M) { - // fprintf(stderr, "DEBUG: Module %s Function %s\n", - // M.getName().str().c_str(), F.getName().str().c_str()); + /*For debugging + AttributeSet X = F.getAttributes().getFnAttributes(); + fprintf(stderr, "DEBUG: Module %s Function %s attributes %u\n", + M.getName().str().c_str(), F.getName().str().c_str(), + X.getNumAttributes()); + */ if (F.size() < function_minimum_size) continue; if (isIgnoreFunction(&F)) continue; + if (module_block_list.size()) { + + for (auto bname : module_block_list) { + + std::string fname = F.getName().str(); + + if (fname.compare(bname) == 0) { + + if (!be_quiet) + WARNF( + "Skipping instrumentation of dangerous early running function " + "%s", + fname.c_str()); + + } + + } + + } + // the instrument file list check AttributeList Attrs = F.getAttributes(); if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 32903d2f..c69d8bb7 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -329,10 +329,13 @@ static void __afl_map_shm(void) { id_str = getenv(CMPLOG_SHM_ENV_VAR); - if (getenv("AFL_DEBUG")) + if (getenv("AFL_DEBUG")) { + fprintf(stderr, "DEBUG: cmplog id_str %s\n", id_str == NULL ? "<null>" : id_str); + } + if (id_str) { #ifdef USEMMAP @@ -404,9 +407,12 @@ static void __afl_start_snapshots(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); - if (getenv("AFL_DEBUG")) + if (getenv("AFL_DEBUG")) { + fprintf(stderr, "target forkserver recv: %08x\n", was_killed); + } + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { @@ -613,9 +619,12 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); - if (getenv("AFL_DEBUG")) + if (getenv("AFL_DEBUG")) { + fprintf(stderr, "target forkserver recv: %08x\n", was_killed); + } + if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { @@ -936,8 +945,12 @@ void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { u32 inst_ratio = 100; char *x; - fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n", start, - stop); + if (getenv("AFL_DEBUG")) { + + fprintf(stderr, "Running __sanitizer_cov_trace_pc_guard_init: %p-%p\n", + start, stop); + + } if (start == stop || *start) return; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 4dc5e438..adb75a2d 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -293,8 +293,8 @@ static void report_error_and_exit(int error) { FATAL( "the fuzzing target reports that hardcoded map address might be the " "reason the mmap of the shared memory failed. Solution: recompile " - "the target with either afl-clang-lto and the environment variable " - "AFL_LLVM_MAP_DYNAMIC set or recompile with afl-clang-fast."); + "the target with either afl-clang-lto and do not set " + "AFL_LLVM_MAP_ADDR or recompile with afl-clang-fast."); break; case FS_ERROR_SHM_OPEN: FATAL("the fuzzing target reports that the shm_open() call failed."); @@ -838,8 +838,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, SAYF("\n" cLRD "[-] " cRST "Hmm, looks like the target binary terminated before we could" " complete a handshake with the injected code.\n" - "If the target was compiled with afl-clang-lto then recompiling with" - " AFL_LLVM_MAP_DYNAMIC might solve your problem.\n" + "If the target was compiled with afl-clang-lto and AFL_LLVM_MAP_ADDR" + " then recompiling without this parameter.\n" "Otherwise there is a horrible bug in the fuzzer.\n" "Poke <afl-users@googlegroups.com> for troubleshooting tips.\n"); @@ -870,9 +870,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, " - the target was compiled with afl-clang-lto and a constructor " "was\n" - " instrumented, recompiling with AFL_LLVM_MAP_DYNAMIC might solve " - "your\n" - " problem\n\n" + " instrumented, recompiling without AFL_LLVM_MAP_ADDR might solve " + "your problem\n\n" " - Less likely, there is a horrible bug in the fuzzer. If other " "options\n" diff --git a/src/afl-fuzz-cmplog.c b/src/afl-fuzz-cmplog.c index faf4dcb7..8ffc6e1b 100644 --- a/src/afl-fuzz-cmplog.c +++ b/src/afl-fuzz-cmplog.c @@ -29,10 +29,6 @@ #include "afl-fuzz.h" #include "cmplog.h" -typedef struct cmplog_data { - -} cmplog_data_t; - void cmplog_exec_child(afl_forkserver_t *fsrv, char **argv) { setenv("___AFL_EINS_ZWEI_POLIZEI___", "1", 1); diff --git a/src/afl-fuzz-mutators.c b/src/afl-fuzz-mutators.c index b30106a0..0fa646f9 100644 --- a/src/afl-fuzz-mutators.c +++ b/src/afl-fuzz-mutators.c @@ -142,6 +142,7 @@ struct custom_mutator *load_custom_mutator(afl_state_t *afl, const char *fn) { struct custom_mutator *mutator = ck_alloc(sizeof(struct custom_mutator)); mutator->name = fn; + mutator->name_short = strrchr(fn, '/') + 1; ACTF("Loading custom mutator library from '%s'...", fn); dh = dlopen(fn, RTLD_NOW); diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 75687703..9f38b8f8 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -1764,6 +1764,8 @@ custom_mutator_stage: has_custom_fuzz = true; + afl->stage_short = el->name_short; + for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) { diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 0aef1c9e..9db23134 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -138,7 +138,7 @@ void write_to_testcase(afl_state_t *afl, void *mem, u32 len) { /* The same, but with an adjustable gap. Used for trimming. */ -static void write_with_gap(afl_state_t *afl, void *mem, u32 len, u32 skip_at, +static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, u32 skip_len) { s32 fd = afl->fsrv.out_fd; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index fc9cbb6c..11db004d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -300,9 +300,12 @@ int main(int argc, char **argv_orig, char **envp) { if (afl->cpu_to_bind != -1) FATAL("Multiple -b options not supported"); - if (sscanf(optarg, "%u", &afl->cpu_to_bind) < 0 || optarg[0] == '-') + if (sscanf(optarg, "%d", &afl->cpu_to_bind) < 0) { + FATAL("Bad syntax used for -b"); + } + break; } diff --git a/test/test-basic.sh b/test/test-basic.sh index 5ce5630b..9e4b03c3 100755 --- a/test/test-basic.sh +++ b/test/test-basic.sh @@ -120,7 +120,7 @@ test "$SYS" = "i686" -o "$SYS" = "x86_64" -o "$SYS" = "amd64" -o "$SYS" = "i86pc } } || { $ECHO "$YELLOW[-] not an intel platform, cannot test afl-gcc" - INCOMPLETE=1 + #this is not incomplete as this feature doesnt exist, so all good } . ./test-post.sh |