From 45d0e4765e9b60f4107fcf87a128ce521bf2665b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Sat, 8 Aug 2020 19:37:15 +0200 Subject: fix stderr output --- llvm_mode/afl-llvm-rt.o.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'llvm_mode') diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c index 8cc59cbb..623e3a20 100644 --- a/llvm_mode/afl-llvm-rt.o.c +++ b/llvm_mode/afl-llvm-rt.o.c @@ -327,10 +327,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 ? "" : id_str); + } + if (id_str) { #ifdef USEMMAP @@ -402,9 +405,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)) { @@ -611,9 +617,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)) { @@ -908,8 +917,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; -- cgit 1.4.1 From 701fb95d24cd754e9c116d81502b6057a29eb2bd Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 10 Aug 2020 23:42:33 +0200 Subject: LTO: make dynamic map the default --- docs/Changelog.md | 2 ++ llvm_mode/README.lto.md | 20 ++++------------- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 33 +++++++++++++++++++++++----- src/afl-forkserver.c | 13 +++++------ 4 files changed, 40 insertions(+), 28 deletions(-) (limited to 'llvm_mode') diff --git a/docs/Changelog.md b/docs/Changelog.md index f8742b1c..182a15b8 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -28,6 +28,8 @@ sending a mail to . 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: autodictionary mode is a default - LTO: instrim instrumentation disabled, only classic support used as it is always better 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..ddfcb400 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,21 @@ bool AFLLTOPass::runOnModule(Module &M) { } - */ + */ + + if (map_addr) + for (GlobalIFunc &IF : M.ifuncs()) { + + // No clue how to follow these up and find the resolver function. + // If we would know that resolver function name we could just skip + // instrumenting it and everything would be fine :-( + // StringRef ifunc_name = IF.getName(); + // Constant *r = IF.getResolver(); + FATAL( + "Target uses ifunc attribute, dynamic map cannot be used, remove " + "AFL_LLVM_MAP_DYNAMIC"); + + } /* Instrument all the things! */ @@ -220,8 +239,12 @@ 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; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 752641d7..1ececf27 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."); @@ -828,8 +828,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 for troubleshooting tips.\n"); @@ -860,9 +860,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" -- cgit 1.4.1 From 1e38c10efb572efac2638366f18a1cf23acd7c2b Mon Sep 17 00:00:00 2001 From: van Hauser Date: Mon, 10 Aug 2020 23:48:13 +0200 Subject: remove warning, fix text --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 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 ddfcb400..1933ed8d 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -228,8 +228,9 @@ bool AFLLTOPass::runOnModule(Module &M) { // StringRef ifunc_name = IF.getName(); // Constant *r = IF.getResolver(); FATAL( - "Target uses ifunc attribute, dynamic map cannot be used, remove " - "AFL_LLVM_MAP_DYNAMIC"); + "Target uses ifunc attribute for %s, fixed map cannot be used, " + "remove AFL_LLVM_MAP_ADDR", + IF.getName().str().c_str()); } -- cgit 1.4.1 From 432638404f40594ae163b6e1b92fcfd51b59d59a Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 11 Aug 2020 01:31:44 +0200 Subject: ignoring ifuncs on fixed map LTO --- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 47 ++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 10 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 1933ed8d..abc836aa 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -219,21 +219,30 @@ bool AFLLTOPass::runOnModule(Module &M) { */ - if (map_addr) + std::vector module_block_list; + + if (map_addr) { + for (GlobalIFunc &IF : M.ifuncs()) { + + StringRef ifunc_name = IF.getName(); + Constant *r = IF.getResolver(); + StringRef r_name = cast(r->getOperand(0))->getName(); + if (!be_quiet) + fprintf(stderr, "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()); - // No clue how to follow these up and find the resolver function. - // If we would know that resolver function name we could just skip - // instrumenting it and everything would be fine :-( - // StringRef ifunc_name = IF.getName(); - // Constant *r = IF.getResolver(); - FATAL( - "Target uses ifunc attribute for %s, fixed map cannot be used, " - "remove AFL_LLVM_MAP_ADDR", - IF.getName().str().c_str()); + module_block_list.push_back(r_name.str()); } + // next up: ctors run before __afl_init() + + // TODO + + + } + /* Instrument all the things! */ int inst_blocks = 0; @@ -250,6 +259,24 @@ bool AFLLTOPass::runOnModule(Module &M) { 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 ifunc resolver function %s", + fname.c_str()); + + } + + } + + } + // the instrument file list check AttributeList Attrs = F.getAttributes(); if (Attrs.hasAttribute(-1, StringRef("skipinstrument"))) { -- cgit 1.4.1 From 50e76fce123f01ec83024f3bbd3190f2e1a6d387 Mon Sep 17 00:00:00 2001 From: van Hauser Date: Tue, 11 Aug 2020 02:05:39 +0200 Subject: adding ctor function skipping in LTO fixed map mode --- docs/Changelog.md | 1 + include/debug.h | 52 +++++++++---------- llvm_mode/afl-llvm-lto-instrumentation.so.cc | 76 +++++++++++++++++++++++----- 3 files changed, 90 insertions(+), 39 deletions(-) (limited to 'llvm_mode') diff --git a/docs/Changelog.md b/docs/Changelog.md index 182a15b8..25c7a761 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -30,6 +30,7 @@ sending a mail to . 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/debug.h b/include/debug.h index 6cc26ec2..f9ebce58 100644 --- a/include/debug.h +++ b/include/debug.h @@ -218,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); \ +#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); \ - \ + __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); \ +#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(); \ - \ + __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); \ +#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); \ - \ + __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/afl-llvm-lto-instrumentation.so.cc b/llvm_mode/afl-llvm-lto-instrumentation.so.cc index abc836aa..fd8e48a7 100644 --- a/llvm_mode/afl-llvm-lto-instrumentation.so.cc +++ b/llvm_mode/afl-llvm-lto-instrumentation.so.cc @@ -224,22 +224,70 @@ bool AFLLTOPass::runOnModule(Module &M) { if (map_addr) { for (GlobalIFunc &IF : M.ifuncs()) { - + StringRef ifunc_name = IF.getName(); Constant *r = IF.getResolver(); StringRef r_name = cast(r->getOperand(0))->getName(); if (!be_quiet) - fprintf(stderr, "Found an ifunc with name %s that points to resolver function %s, we cannot instrument this, putting it into a block list.\n", + 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()); } - // next up: ctors run before __afl_init() - - // TODO + GlobalVariable *GV = M.getNamedGlobal("llvm.global_ctors"); + if (GV && !GV->isDeclaration() && !GV->hasLocalLinkage()) { + + ConstantArray *InitList = dyn_cast(GV->getInitializer()); + + if (InitList) { + + for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { + + if (ConstantStruct *CS = + dyn_cast(InitList->getOperand(i))) { + + if (CS->getNumOperands() >= 2) { + if (CS->getOperand(1)->isNullValue()) + break; // Found a null terminator, stop here. + + ConstantInt *CI = dyn_cast(CS->getOperand(0)); + int Priority = CI ? CI->getSExtValue() : 0; + + Constant *FP = CS->getOperand(1); + if (ConstantExpr *CE = dyn_cast(FP)) + if (CE->isCast()) FP = CE->getOperand(0); + if (Function *F = dyn_cast(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()); + + } + + } + + } + + } + + } + + } + + } } @@ -260,21 +308,23 @@ bool AFLLTOPass::runOnModule(Module &M) { 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 ifunc resolver function %s", - fname.c_str()); - + WARNF( + "Skipping instrumentation of dangerous early running function " + "%s", + fname.c_str()); + } - + } - + } // the instrument file list check -- cgit 1.4.1