From dde0538b484df627dac14ff030dd09f55c78558e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 28 Apr 2021 10:59:34 +0200 Subject: nits --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 520b13b1..90a1d140 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,7 @@ sending a mail to . ### Version ++3.13a (development) - frida_mode - new mode that uses frida to fuzz binary-only targets, + it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! - create a fuzzing dictionary with the help of CodeQL thanks to @microsvuln! see utils/autodict_ql -- cgit 1.4.1 From c9d066038fe0bbf8e0ab0a481ca320ca1c31b1bf Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 10:27:43 +0200 Subject: fix PCGUARD, build aflpp_driver with fPIC --- docs/Changelog.md | 5 +- instrumentation/SanitizerCoverageLTO.so.cc | 15 ++-- instrumentation/SanitizerCoveragePCGUARD.so.cc | 102 +++++++++++-------------- utils/afl_proxy/afl-proxy.c | 6 ++ utils/aflpp_driver/GNUmakefile | 4 +- 5 files changed, 64 insertions(+), 68 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 90a1d140..5c0f2a9e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -32,10 +32,13 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - afl-cc: - We do not support llvm versions prior 6.0 anymore + - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode + - utils/aflpp_driver: + - aflpp_qemu_driver_hook fixed to work with qemu_mode + - aflpp_driver now compiled with -fPIC - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 6dd390e6..2f4337eb 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -60,15 +60,14 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -// static const char *const SanCovTracePCGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +// const char SanCovTracePCGuardName = // "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; static cl::opt ClCoverageLevel( "lto-coverage-level", diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 09cda9e2..8878d3b1 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -52,49 +52,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; -static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; -static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; -static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; -static const char *const SanCovTraceConstCmp1 = - "__sanitizer_cov_trace_const_cmp1"; -static const char *const SanCovTraceConstCmp2 = - "__sanitizer_cov_trace_const_cmp2"; -static const char *const SanCovTraceConstCmp4 = - "__sanitizer_cov_trace_const_cmp4"; -static const char *const SanCovTraceConstCmp8 = - "__sanitizer_cov_trace_const_cmp8"; -static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; -static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; -static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; -static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; -static const char *const SanCovModuleCtorTracePcGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -static const char *const SanCovModuleCtor8bitCountersName = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -static const char *const SanCovModuleCtorBoolFlagName = - "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -static const char *const SanCovTracePCGuardName = - "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovTracePCGuardInitName = - "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName = - "__sanitizer_cov_8bit_counters_init"; -static const char *const SanCovBoolFlagInitName = - "__sanitizer_cov_bool_flag_init"; -static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static char *skip_nozero; @@ -320,12 +310,12 @@ std::pair ModuleSanitizerCoverage::CreateSecStartEnd( Module &M, const char *Section, Type *Ty) { GlobalVariable *SecStart = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionStart(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); GlobalVariable *SecEnd = new GlobalVariable( - M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + M, Ty->getPointerElementType(), false, + GlobalVariable::ExternalWeakLinkage, nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); if (!TargetTriple.isOSBinFormatCOFF()) @@ -573,7 +563,7 @@ bool ModuleSanitizerCoverage::instrumentModule( } // True if block has successors and it dominates all of them. -static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { +bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { if (succ_begin(BB) == succ_end(BB)) return false; @@ -588,8 +578,7 @@ static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { } // True if block has predecessors and it postdominates all of them. -static bool isFullPostDominator(const BasicBlock * BB, - const PostDominatorTree *PDT) { +bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { if (pred_begin(BB) == pred_end(BB)) return false; @@ -603,10 +592,10 @@ static bool isFullPostDominator(const BasicBlock * BB, } -static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, - const DominatorTree * DT, - const PostDominatorTree * PDT, - const SanitizerCoverageOptions &Options) { +bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, + const DominatorTree * DT, + const PostDominatorTree * PDT, + const SanitizerCoverageOptions &Options) { // Don't insert coverage for blocks containing nothing but unreachable: we // will never call __sanitizer_cov() for them, so counting them in @@ -636,8 +625,7 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, // A twist here is that we treat From->To as a backedge if // * To dominates From or // * To->UniqueSuccessor dominates From -static bool IsBackEdge(BasicBlock *From, BasicBlock *To, - const DominatorTree *DT) { +bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { if (DT->dominates(To, From)) return true; if (auto Next = To->getUniqueSuccessor()) @@ -651,8 +639,8 @@ static bool IsBackEdge(BasicBlock *From, BasicBlock *To, // // Note that Cmp pruning is controlled by the same flag as the // BB pruning. -static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, - const SanitizerCoverageOptions &Options) { +bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, + const SanitizerCoverageOptions &Options) { if (!Options.NoPrune) if (CMP->hasOneUse()) @@ -1046,7 +1034,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, if (IsEntryBB) { - // Keep static allocas and llvm.localescape calls in the entry block. Even + // Keep allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. IP = PrepareToSplitEntryBlock(BB, IP); @@ -1221,17 +1209,17 @@ ModulePass *llvm::createModuleSanitizerCoverageLegacyPassPass( } -static void registerPCGUARDPass(const PassManagerBuilder &, - legacy::PassManagerBase &PM) { +void registerPCGUARDPass(const PassManagerBuilder &, + legacy::PassManagerBase &PM) { auto p = new ModuleSanitizerCoverageLegacyPass(); PM.add(p); } -static RegisterStandardPasses RegisterCompTransPass( +RegisterStandardPasses RegisterCompTransPass( PassManagerBuilder::EP_OptimizerLast, registerPCGUARDPass); -static RegisterStandardPasses RegisterCompTransPass0( +RegisterStandardPasses RegisterCompTransPass0( PassManagerBuilder::EP_EnabledOnOptLevel0, registerPCGUARDPass); diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index aa7a361a..a80d8a0b 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -70,12 +70,18 @@ static void __afl_map_shm(void) { char *id_str = getenv(SHM_ENV_VAR); char *ptr; + + /* NOTE TODO BUG FIXME: if you want to supply a variable sized map then + uncomment the following: */ + + /* if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { u32 val = atoi(ptr); if (val > 0) __afl_map_size = val; } + */ if (__afl_map_size > MAP_SIZE) { diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index 8ac054a6..556f6420 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -7,7 +7,7 @@ ifneq "" "$(LLVM_BINDIR)" LLVM_BINDIR := $(LLVM_BINDIR)/ endif -CFLAGS := -O3 -funroll-loops -g +CFLAGS := -O3 -funroll-loops -g -fPIC all: libAFLDriver.a libAFLQemuDriver.a aflpp_qemu_driver_hook.so @@ -36,7 +36,7 @@ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o -$(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -$(LLVM_BINDIR)clang -fPIC $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c + -$(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c -- cgit 1.4.1 From caf282040ffe45509b7cb37cc7c087c22bfdf034 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 11:09:49 +0200 Subject: update changelog --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 5c0f2a9e..459c2f35 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -39,6 +39,7 @@ sending a mail to . - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC + - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup ### Version ++3.12c (release) -- cgit 1.4.1 From 86452cc959bd4b0d5fe6e60d0eefbc7848fe38e2 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 30 Apr 2021 23:41:06 +0200 Subject: fix stdin trimming --- docs/Changelog.md | 1 + src/afl-forkserver.c | 2 +- src/afl-fuzz-run.c | 10 ++++------ utils/afl_proxy/afl-proxy.c | 23 +++++++++++++++-------- 4 files changed, 21 insertions(+), 15 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 459c2f35..6a25865d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . - add recording of previous fuzz attempts for persistent mode to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h + - fixed a bug when trimming for stdin targets - default cmplog level (-l) is now 2, better efficiency. - cmplog level 3 (-l 3) now performs redqueen on everything. use with care. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index d533fd4a..a07e78b4 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1090,7 +1090,7 @@ void afl_fsrv_write_to_testcase(afl_forkserver_t *fsrv, u8 *buf, size_t len) { #endif - if (likely(fsrv->use_shmem_fuzz && fsrv->shmem_fuzz)) { + if (likely(fsrv->use_shmem_fuzz)) { if (unlikely(len > MAX_FILE)) len = MAX_FILE; diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index a7b071a5..397d62bf 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -203,7 +203,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (afl->fsrv.shmem_fuzz) { + if (likely(afl->fsrv.use_shmem_fuzz)) { if (!post_process_skipped) { @@ -211,9 +211,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, memcpy(afl->fsrv.shmem_fuzz, new_mem, new_size); - } - - else { + } else { memcpy(afl->fsrv.shmem_fuzz, mem, skip_at); @@ -244,7 +242,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, return; - } else if (afl->fsrv.out_file) { + } else if (unlikely(!afl->fsrv.use_stdin)) { if (unlikely(afl->no_unlink)) { @@ -279,7 +277,7 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, } - if (!afl->fsrv.out_file) { + if (afl->fsrv.use_stdin) { if (ftruncate(fd, new_size)) { PFATAL("ftruncate() failed"); } lseek(fd, 0, SEEK_SET); diff --git a/utils/afl_proxy/afl-proxy.c b/utils/afl_proxy/afl-proxy.c index 2d8ba991..6006e238 100644 --- a/utils/afl_proxy/afl-proxy.c +++ b/utils/afl_proxy/afl-proxy.c @@ -195,10 +195,7 @@ static u32 __afl_next_testcase(u8 *buf, u32 max_len) { /* report that we are starting the target */ if (write(FORKSRV_FD + 1, &res, 4) != 4) return 0; - if (status < 1) - return 0; - else - return status; + return status; } @@ -216,7 +213,7 @@ int main(int argc, char *argv[]) { /* This is were the testcase data is written into */ u8 buf[1024]; // this is the maximum size for a test case! set it! - u32 len; + s32 len; /* here you specify the map size you need that you are reporting to afl-fuzz. Any value is fine as long as it can be divided by 32. */ @@ -228,10 +225,20 @@ int main(int argc, char *argv[]) { while ((len = __afl_next_testcase(buf, sizeof(buf))) > 0) { - /* here you have to create the magic that feeds the buf/len to the - target and write the coverage to __afl_area_ptr */ + if (len > 4) { // the minimum data size you need for the target - // ... the magic ... + /* here you have to create the magic that feeds the buf/len to the + target and write the coverage to __afl_area_ptr */ + + // ... the magic ... + + // remove this, this is just to make afl-fuzz not complain when run + if (buf[0] == 0xff) + __afl_area_ptr[1] = 1; + else + __afl_area_ptr[2] = 2; + + } /* report the test case is done and wait for the next */ __afl_end_testcase(); -- cgit 1.4.1 From 6dc82e620b744b61ce4ad6d783f59b9c9db2827a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 6 May 2021 12:06:58 +0200 Subject: unicorn mips fixes --- docs/Changelog.md | 2 ++ unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6a25865d..0aef1e33 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -40,6 +40,8 @@ sending a mail to . - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC + - unicornafl: + - fix MIPS delay slot caching, thanks @JackGrence - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index d9ae5590..e766d2f5 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -fb2fc9f2 +f59df67375c5914321842767636a9fa6f692d5a1 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index fb2fc9f2..f59df673 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit fb2fc9f25df32f17f6b6b859e4dbd70f9a857e0c +Subproject commit f59df67375c5914321842767636a9fa6f692d5a1 -- cgit 1.4.1 From 7317a594fe5d839019d934b9c269cde146361e34 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 6 May 2021 17:14:42 +0200 Subject: unicorn fixes --- docs/Changelog.md | 2 ++ unicorn_mode/UNICORNAFL_VERSION | 2 +- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0aef1e33..31351a58 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -42,6 +42,8 @@ sending a mail to . - aflpp_driver now compiled with -fPIC - unicornafl: - fix MIPS delay slot caching, thanks @JackGrence + - fixed aarch64 exit address + - execution no longer stops at address 0x0 - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup diff --git a/unicorn_mode/UNICORNAFL_VERSION b/unicorn_mode/UNICORNAFL_VERSION index e766d2f5..7677c3db 100644 --- a/unicorn_mode/UNICORNAFL_VERSION +++ b/unicorn_mode/UNICORNAFL_VERSION @@ -1 +1 @@ -f59df67375c5914321842767636a9fa6f692d5a1 +3a8957fbf25b1cc9e58d59474f4a3dc0654801e3 diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index f59df673..3a8957fb 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit f59df67375c5914321842767636a9fa6f692d5a1 +Subproject commit 3a8957fbf25b1cc9e58d59474f4a3dc0654801e3 -- cgit 1.4.1 From 84e55e7a1bc684b2f3b52db4d6e789135af95d13 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 10 May 2021 10:38:31 +0200 Subject: arch linux and mac os support for afl-system-config --- afl-system-config | 10 +++++++--- docs/Changelog.md | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/afl-system-config b/afl-system-config index 5ad9d937..e08871ac 100755 --- a/afl-system-config +++ b/afl-system-config @@ -22,7 +22,10 @@ if [ '!' "$EUID" = 0 ] && [ '!' `id -u` = 0 ] ; then fi if [ "$PLATFORM" = "Linux" ] ; then { - sysctl -w kernel.core_pattern=core + sysctl -w kernel.core_uses_pid=0 + # Arch Linux requires core_pattern to be empty :( + test -e /etc/arch-release && sysctl -w kernel.core_pattern= + test -e /etc/arch-release || sysctl -w kernel.core_pattern=core sysctl -w kernel.randomize_va_space=0 sysctl -w kernel.sched_child_runs_first=1 sysctl -w kernel.sched_autogroup_enabled=1 @@ -86,14 +89,15 @@ if [ "$PLATFORM" = "NetBSD" ] ; then DONE=1 fi if [ "$PLATFORM" = "Darwin" ] ; then + sysctl kern.sysv.shmmax=8388608 + sysctl kern.sysv.shmseg=48 + sysctl kern.sysv.shmall=98304 if [ $(launchctl list 2>/dev/null | grep -q '\.ReportCrash$') ] ; then echo We unload the default crash reporter here SL=/System/Library; PL=com.apple.ReportCrash launchctl unload -w ${SL}/LaunchAgents/${PL}.plist sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist echo Settings applied. - else - echo Nothing to do. fi DONE=1 fi diff --git a/docs/Changelog.md b/docs/Changelog.md index 31351a58..ceb02bb9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -44,6 +44,8 @@ sending a mail to . - fix MIPS delay slot caching, thanks @JackGrence - fixed aarch64 exit address - execution no longer stops at address 0x0 + - updated afl-system-config to support Arch Linux weirdness and increase + MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup -- cgit 1.4.1 From 72ca9b4684981ce2b807e4efd218bd1924f3e6b1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 11 May 2021 22:06:37 +0200 Subject: fix a few cur_time uses --- docs/Changelog.md | 1 + src/afl-cc.c | 16 +++++++++------- src/afl-fuzz-one.c | 6 +++--- src/afl-fuzz-stats.c | 5 +++-- src/afl-fuzz.c | 6 ++++-- 5 files changed, 20 insertions(+), 14 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index ceb02bb9..e4c02921 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,6 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.13a (development) + - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. thanks to @WorksButNotTested! diff --git a/src/afl-cc.c b/src/afl-cc.c index c1050355..ff7b5219 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1574,12 +1574,12 @@ int main(int argc, char **argv, char **envp) { else if (have_gcc_plugin) compiler_mode = GCC_PLUGIN; else if (have_gcc) - #ifdef __APPLE__ - // on OSX clang masquerades as GCC - compiler_mode = CLANG; - #else - compiler_mode = GCC; - #endif +#ifdef __APPLE__ + // on OSX clang masquerades as GCC + compiler_mode = CLANG; +#else + compiler_mode = GCC; +#endif else if (have_lto) compiler_mode = LTO; else @@ -1602,8 +1602,10 @@ int main(int argc, char **argv, char **envp) { } if (compiler_mode == CLANG) { + instrument_mode = INSTRUMENT_CLANG; - setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + setenv(CLANG_ENV_VAR, "1", 1); // used by afl-as + } if (argc < 2 || strncmp(argv[1], "-h", 2) == 0) { diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4eeb93de..4a3e7f33 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -562,7 +562,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { @@ -2013,7 +2013,7 @@ havoc_stage: } - if (unlikely(get_cur_time() - afl->last_path_time > 5000 && + if (unlikely(get_cur_time() - afl->last_path_time > 5000 /* 5 seconds */ && afl->ready_for_splicing_count > 1)) { /* add expensive havoc cases here if there is no findings in the last 5s */ @@ -3060,7 +3060,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || !(afl->fsrv.total_execs % afl->queued_paths) || - get_cur_time() - afl->last_path_time > 300000) { + get_cur_time() - afl->last_path_time > 300000) { // 300 seconds if (input_to_state_stage(afl, in_buf, out_buf, len)) { diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 313263f9..4884b942 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -368,7 +368,8 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, afl->plot_prev_uh == afl->unique_hangs && afl->plot_prev_md == afl->max_depth && afl->plot_prev_ed == afl->fsrv.total_execs) || - !afl->queue_cycle || get_cur_time() - afl->start_time <= 60))) { + !afl->queue_cycle || + get_cur_time() - afl->start_time <= 60000))) { return; @@ -393,7 +394,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg, fprintf(afl->fsrv.plot_file, "%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%u\n", - (afl->prev_run_time + get_cur_time() - afl->start_time), + ((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000), afl->queue_cycle - 1, afl->current_entry, afl->queued_paths, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->unique_crashes, afl->unique_hangs, afl->max_depth, eps, diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 8de3ed6b..094fd161 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1940,8 +1940,10 @@ int main(int argc, char **argv_orig, char **envp) { /* If we had a full queue cycle with no new finds, try recombination strategies next. */ - if (unlikely(afl->queued_paths == prev_queued && - (get_cur_time() - afl->start_time) >= 3600)) { + if (unlikely(afl->queued_paths == prev_queued + /* FIXME TODO BUG: && (get_cur_time() - afl->start_time) >= + 3600 */ + )) { if (afl->use_splicing) { -- cgit 1.4.1 From 47e22e8d8d383078989906c6fe54a9ec4deff8c1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 17 May 2021 16:52:52 +0200 Subject: no core dumps --- docs/Changelog.md | 1 + src/afl-forkserver.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index e4c02921..4fa70bfd 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,6 +29,7 @@ sending a mail to . - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a07e78b4..0286ab47 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -451,8 +451,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, /* 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 */ + if (!fsrv->debug) { + + r.rlim_max = r.rlim_cur = 0; + setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + + } /* Isolate the process and configure standard descriptors. If out_file is specified, stdin is /dev/null; otherwise, out_fd is cloned instead. */ -- cgit 1.4.1 From ccf739f8801c373fe2aa1bb709ffd697cfe2a3e6 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:16:41 +0200 Subject: AFL_PRINT_FILENAMES added --- afl-cmin | 2 ++ docs/Changelog.md | 1 + docs/env_variables.md | 3 ++ src/afl-showmap.c | 82 ++++++++++++++++++++++++++++----------------------- 4 files changed, 51 insertions(+), 37 deletions(-) (limited to 'docs/Changelog.md') diff --git a/afl-cmin b/afl-cmin index 3f3a7517..adcbb221 100755 --- a/afl-cmin +++ b/afl-cmin @@ -123,6 +123,8 @@ function usage() { "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal ID delivered to child processes on timeout, etc. (default: SIGKILL)\n" "AFL_PATH: path for the afl-showmap binary if not found anywhere else\n" \ +"AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ + "printed to stdout\n" \ "AFL_SKIP_BIN_CHECK: skip check for target binary\n" exit 1 } diff --git a/docs/Changelog.md b/docs/Changelog.md index 4fa70bfd..67ab9d5e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -50,6 +50,7 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index 8879db72..99568146 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -567,6 +567,9 @@ The corpus minimization script offers very little customization: a modest security risk on multi-user systems with rogue users, but should be safe on dedicated fuzzing boxes. + - `AFL_PRINT_FILENAMES` prints each filename to stdout, as it gets processed. + This can help when embedding `afl-cmin` or `afl-showmap` in other scripts scripting. + ## 7) Settings for afl-tmin Virtually nothing to play with. Well, in QEMU mode (`-Q`), `AFL_PATH` will be diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 41a62108..336ac126 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -76,17 +76,18 @@ static u32 in_len; /* Input data length */ static u32 map_size = MAP_SIZE; -static u8 quiet_mode, /* Hide non-essential messages? */ +static bool quiet_mode, /* Hide non-essential messages? */ edges_only, /* Ignore hit counts? */ raw_instr_output, /* Do not apply AFL filters */ cmin_mode, /* Generate output in afl-cmin mode? */ binary_mode, /* Write output as a binary map */ keep_cores, /* Allow coredumps? */ - remove_shm = 1, /* remove shmem? */ + remove_shm = true, /* remove shmem? */ collect_coverage, /* collect coverage */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ - debug; /* debug mode */ + debug, /* debug mode */ + print_filenames; /* print the current filename */ static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -320,11 +321,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -335,11 +336,11 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(fsrv->child_status)) { - child_crashed = 1; + child_crashed = true; } else { - child_crashed = 0; + child_crashed = false; } @@ -375,6 +376,8 @@ static void showmap_run_target_forkserver(afl_forkserver_t *fsrv, u8 *mem, static u32 read_file(u8 *in_file) { + if (print_filenames) { SAYF("Processing %s\n", in_file); } + struct stat st; s32 fd = open(in_file, O_RDONLY); @@ -515,11 +518,11 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (fsrv->trace_bits[0] == 1) { fsrv->trace_bits[0] = 0; - have_coverage = 1; + have_coverage = true; } else { - have_coverage = 0; + have_coverage = false; } @@ -529,7 +532,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { if (!fsrv->last_run_timed_out && !stop_soon && WIFSIGNALED(status)) { - child_crashed = 1; + child_crashed = true; } @@ -559,7 +562,7 @@ static void showmap_run_target(afl_forkserver_t *fsrv, char **argv) { static void handle_stop_sig(int sig) { (void)sig; - stop_soon = 1; + stop_soon = true; afl_fsrv_killall(); } @@ -742,6 +745,8 @@ static void usage(u8 *argv0) { "AFL_MAP_SIZE: the shared memory size for that target. must be >= the " "size the target was compiled for\n" "AFL_PRELOAD: LD_PRELOAD / DYLD_INSERT_LIBRARIES settings for target\n" + "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " + "printed to stdout\n" "AFL_QUIET: do not print extra informational output\n", argv0, MEM_LIMIT, doc_path); @@ -755,14 +760,17 @@ int main(int argc, char **argv_orig, char **envp) { // TODO: u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ - s32 opt, i; - u8 mem_limit_given = 0, timeout_given = 0, unicorn_mode = 0, use_wine = 0; + s32 opt, i; + bool mem_limit_given = false, timeout_given = false, unicorn_mode = false, + use_wine = false; char **use_argv; char **argv = argv_cpy_dup(argc, argv_orig); afl_forkserver_t fsrv_var = {0}; - if (getenv("AFL_DEBUG")) { debug = 1; } + if (getenv("AFL_DEBUG")) { debug = true; } + if (getenv("AFL_PRINT_FILENAMES")) { print_filenames = true; } + fsrv = &fsrv_var; afl_fsrv_init(fsrv); map_size = get_map_size(); @@ -770,19 +778,19 @@ int main(int argc, char **argv_orig, char **envp) { doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH; - if (getenv("AFL_QUIET") != NULL) { be_quiet = 1; } + if (getenv("AFL_QUIET") != NULL) { be_quiet = true; } while ((opt = getopt(argc, argv, "+i:o:f:m:t:A:eqCZOQUWbcrsh")) > 0) { switch (opt) { case 's': - no_classify = 1; + no_classify = true; break; case 'C': - collect_coverage = 1; - quiet_mode = 1; + collect_coverage = true; + quiet_mode = true; break; case 'i': @@ -801,7 +809,7 @@ int main(int argc, char **argv_orig, char **envp) { u8 suffix = 'M'; if (mem_limit_given) { FATAL("Multiple -m options not supported"); } - mem_limit_given = 1; + mem_limit_given = true; if (!optarg) { FATAL("Wrong usage of -m"); } @@ -862,7 +870,7 @@ int main(int argc, char **argv_orig, char **envp) { case 't': if (timeout_given) { FATAL("Multiple -t options not supported"); } - timeout_given = 1; + timeout_given = true; if (!optarg) { FATAL("Wrong usage of -t"); } @@ -884,12 +892,12 @@ int main(int argc, char **argv_orig, char **envp) { if (edges_only) { FATAL("Multiple -e options not supported"); } if (raw_instr_output) { FATAL("-e and -r are mutually exclusive"); } - edges_only = 1; + edges_only = true; break; case 'q': - quiet_mode = 1; + quiet_mode = true; break; case 'Z': @@ -897,8 +905,8 @@ int main(int argc, char **argv_orig, char **envp) { /* This is an undocumented option to write data in the syntax expected by afl-cmin. Nobody else should have any use for this. */ - cmin_mode = 1; - quiet_mode = 1; + cmin_mode = true; + quiet_mode = true; break; case 'A': @@ -910,7 +918,7 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->frida_mode) { FATAL("Multiple -O options not supported"); } - fsrv->frida_mode = 1; + fsrv->frida_mode = true; break; @@ -918,21 +926,21 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->qemu_mode) { FATAL("Multiple -Q options not supported"); } - fsrv->qemu_mode = 1; + fsrv->qemu_mode = true; break; case 'U': if (unicorn_mode) { FATAL("Multiple -U options not supported"); } - unicorn_mode = 1; + unicorn_mode = true; break; case 'W': /* Wine+QEMU mode */ if (use_wine) { FATAL("Multiple -W options not supported"); } - fsrv->qemu_mode = 1; - use_wine = 1; + fsrv->qemu_mode = true; + use_wine = true; break; @@ -941,20 +949,20 @@ int main(int argc, char **argv_orig, char **envp) { /* Secret undocumented mode. Writes output in raw binary format similar to that dumped by afl-fuzz in cmplog_mode = 0; u8 *map = afl_shm_init(shm_fuzz, MAX_FILE + sizeof(u32), 1); - shm_fuzz->shmemfuzz_mode = 1; + shm_fuzz->shmemfuzz_mode = true; if (!map) { FATAL("BUG: Zero return from afl_shm_init."); } #ifdef USEMMAP setenv(SHM_FUZZ_ENV_VAR, shm_fuzz->g_shm_file_path, 1); @@ -1073,7 +1081,7 @@ int main(int argc, char **argv_orig, char **envp) { setenv(SHM_FUZZ_ENV_VAR, shm_str, 1); ck_free(shm_str); #endif - fsrv->support_shmem_fuzz = 1; + fsrv->support_shmem_fuzz = true; fsrv->shmem_fuzz_len = (u32 *)map; fsrv->shmem_fuzz = map + sizeof(u32); @@ -1125,7 +1133,7 @@ int main(int argc, char **argv_orig, char **envp) { struct stat statbuf; #endif - if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = 1; + if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -1164,8 +1172,8 @@ int main(int argc, char **argv_orig, char **envp) { if ((coverage_map = (u8 *)malloc(map_size)) == NULL) FATAL("coult not grab memory"); - edges_only = 0; - raw_instr_output = 1; + edges_only = false; + raw_instr_output = true; } -- cgit 1.4.1 From fa63f2652dbcc6016ff5cf4bd8ca0d14954ae769 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 17 May 2021 18:30:37 +0200 Subject: more documentation for AFL_EXIT_ON_TIME --- docs/Changelog.md | 2 ++ docs/env_variables.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 67ab9d5e..1114a834 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,6 +33,8 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after + no new paths have been found for n seconds - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 99568146..c3efa0c0 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -285,8 +285,8 @@ checks or alter some of the more exotic semantics of the tool: convenient for some types of automated jobs. - `AFL_EXIT_ON_TIME` Causes afl-fuzz to terminate if no new paths were - found within a specified period of time. May be convenient for some - types of automated jobs. + found within a specified period of time (in seconds). May be convenient + for some types of automated jobs. - `AFL_EXIT_ON_SEED_ISSUES` will restore the vanilla afl-fuzz behaviour which does not allow crashes or timeout seeds in the initial -i corpus. -- cgit 1.4.1 From 5997a4fc09163c1baa186f5a9d00c4c8668a72b1 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 21 May 2021 10:26:27 +0200 Subject: fix llvm-dict2file --- GNUmakefile | 10 +++++----- docs/Changelog.md | 1 + instrumentation/afl-llvm-dict2file.so.cc | 5 ++++- qemu_mode/libqasan/libqasan.c | 5 ++--- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'docs/Changelog.md') diff --git a/GNUmakefile b/GNUmakefile index 9d98aa00..270746b4 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -503,21 +503,21 @@ code-format: ./.custom-format.py -i instrumentation/*.h ./.custom-format.py -i instrumentation/*.cc ./.custom-format.py -i instrumentation/*.c + ./.custom-format.py -i *.h + ./.custom-format.py -i *.c @#./.custom-format.py -i custom_mutators/*/*.c* # destroys libfuzzer :-( @#./.custom-format.py -i custom_mutators/*/*.h # destroys honggfuzz :-( ./.custom-format.py -i utils/*/*.c* ./.custom-format.py -i utils/*/*.h ./.custom-format.py -i test/*.c + ./.custom-format.py -i frida_mode/src/*.c + ./.custom-format.py -i frida_mode/include/*.h + -./.custom-format.py -i frida_mode/src/*/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.c ./.custom-format.py -i qemu_mode/libcompcov/*.cc ./.custom-format.py -i qemu_mode/libcompcov/*.h ./.custom-format.py -i qemu_mode/libqasan/*.c ./.custom-format.py -i qemu_mode/libqasan/*.h - ./.custom-format.py -i frida_mode/src/*.c - ./.custom-format.py -i frida_mode/include/*.h - -./.custom-format.py -i frida_mode/src/*/*.c - ./.custom-format.py -i *.h - ./.custom-format.py -i *.c .PHONY: test_build diff --git a/docs/Changelog.md b/docs/Changelog.md index 1114a834..282b34cf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -41,6 +41,7 @@ sending a mail to . - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode + - Fixed a crash in llvm dict2file when a strncmp length was -1 - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index c954054b..e2b44b21 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -426,7 +426,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { ConstantInt *ilen = dyn_cast(op2); if (ilen) { - uint64_t literalLength = Str2.size(); + uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); if (literalLength + 1 == optLength) { @@ -434,6 +434,8 @@ bool AFLdict2filePass::runOnModule(Module &M) { } + if (optLength > Str2.length()) { optLength = Str2.length(); } + } valueMap[Str1P] = new std::string(Str2); @@ -532,6 +534,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length()) { optLen = thestring.length(); } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index 2ac0c861..a64db10f 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -69,9 +69,8 @@ __attribute__((constructor)) void __libqasan_init() { __libqasan_is_initialized = 1; __libqasan_init_hooks(); - - if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) - __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); #ifdef DEBUG __qasan_debug = getenv("QASAN_DEBUG") != NULL; -- cgit 1.4.1 From bd1ceb42c4e445babe38a129abf913d447fce9ea Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 22 May 2021 11:43:09 +0200 Subject: added info about showmap queue directions --- docs/Changelog.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 282b34cf..dfd5c393 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -54,6 +54,7 @@ sending a mail to . - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) - afl-fuzz: -- cgit 1.4.1 From 109383f43830010c36b704c682ee537e6474d25a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 09:08:31 +0200 Subject: less executions on variable paths --- docs/Changelog.md | 2 ++ include/config.h | 4 ++-- src/afl-fuzz-run.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index dfd5c393..33d37067 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times + instead of 40 - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/include/config.h b/include/config.h index aa24ea6c..80cdb684 100644 --- a/include/config.h +++ b/include/config.h @@ -154,7 +154,7 @@ cases that show variable behavior): */ #define CAL_CYCLES 8U -#define CAL_CYCLES_LONG 40U +#define CAL_CYCLES_LONG 20U /* Number of subsequent timeouts before abandoning an input file: */ @@ -163,7 +163,7 @@ /* Maximum number of unique hangs or crashes to record: */ #define KEEP_UNIQUE_HANG 500U -#define KEEP_UNIQUE_CRASH 5000U +#define KEEP_UNIQUE_CRASH 10000U /* Baseline number of random tweaks during a single 'havoc' stage: */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 6e5210b8..5a481639 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -410,7 +410,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = CAL_CYCLES_LONG; + afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; } else { -- cgit 1.4.1 From 87b16c4460d34eb775660991732ca0ef0c2f8e78 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 10:45:24 +0200 Subject: add AFL_TRY_AFFINITY --- Dockerfile | 1 + README.md | 4 ++-- docs/Changelog.md | 10 ++++++---- docs/env_variables.md | 3 +++ include/afl-fuzz.h | 2 +- include/envs.h | 1 + src/afl-fuzz-init.c | 34 ++++++++++++++++++++++++---------- src/afl-fuzz-state.c | 7 +++++++ src/afl-fuzz.c | 1 + 9 files changed, 46 insertions(+), 17 deletions(-) (limited to 'docs/Changelog.md') diff --git a/Dockerfile b/Dockerfile index 8f89b9aa..9662ca7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,6 +50,7 @@ RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 0 ENV LLVM_CONFIG=llvm-config-12 ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_TRY_AFFINITY=1 ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 RUN git clone --depth=1 https://github.com/vanhauser-thc/afl-cov /afl-cov diff --git a/README.md b/README.md index cedf706c..69e2d14a 100644 --- a/README.md +++ b/README.md @@ -679,8 +679,8 @@ If you see that an important area or a feature has not been covered so far then try to find an input that is able to reach that and start a new secondary in that fuzzing campaign with that seed as input, let it run for a few minutes, then terminate it. The main node will pick it up and make it available to the -other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` if you have no -free core. +other secondary nodes over time. Set `export AFL_NO_AFFINITY=1` or +`export AFL_TRY_AFFINITY=1` if you have no free core. Note that you in nearly all cases can never reach full coverage. A lot of functionality is usually behind options that were not activated or fuzz e.g. diff --git a/docs/Changelog.md b/docs/Changelog.md index 33d37067..bbe55e3e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -33,10 +33,12 @@ sending a mail to . - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default afl++ ignores these and uses them for splicing instead. - - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after - no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated 8 times - instead of 40 + - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing + after no new paths have been found for n seconds + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of 40 + - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if + it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD diff --git a/docs/env_variables.md b/docs/env_variables.md index 442b0dd0..a3267523 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -312,6 +312,9 @@ checks or alter some of the more exotic semantics of the tool: 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). + - Setting `AFL_TRY_AFFINITY` tries to attempts to bind to a specific CPU core + on Linux systems, but will not terminate if it fails. + - Setting `AFL_NO_AUTODICT` will not load an LTO generated auto dictionary that is compiled into the target. diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index e9a72fc2..4aba3bdf 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -385,7 +385,7 @@ typedef struct afl_env_vars { afl_force_ui, afl_i_dont_care_about_missing_crashes, afl_bench_just_one, afl_bench_until_crash, afl_debug_child, afl_autoresume, afl_cal_fast, afl_cycle_schedules, afl_expand_havoc, afl_statsd, afl_cmplog_only_new, - afl_exit_on_seed_issues; + afl_exit_on_seed_issues, afl_try_affinity; u8 *afl_tmpdir, *afl_custom_mutator_library, *afl_python_module, *afl_path, *afl_hang_tmout, *afl_forksrv_init_tmout, *afl_preload, diff --git a/include/envs.h b/include/envs.h index f1314bad..e7162c0f 100644 --- a/include/envs.h +++ b/include/envs.h @@ -120,6 +120,7 @@ static char *afl_environment_variables[] = { "AFL_LLVM_INSTRUMENT_FILE", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", + "AFL_TRY_AFFINITY", "AFL_LLVM_LTO_STARTID", "AFL_LLVM_LTO_DONTWRITEID", "AFL_NO_ARITH", diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index f2d1fb9b..88b5bc02 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -113,7 +113,7 @@ void bind_to_free_cpu(afl_state_t *afl) { u8 lockfile[PATH_MAX] = ""; s32 i; - if (afl->afl_env.afl_no_affinity) { + if (afl->afl_env.afl_no_affinity && !afl->afl_env.afl_try_affinity) { if (afl->cpu_to_bind != -1) { @@ -130,10 +130,21 @@ void bind_to_free_cpu(afl_state_t *afl) { if (!bind_cpu(afl, afl->cpu_to_bind)) { - FATAL( - "Could not bind to requested CPU %d! Make sure you passed a valid " - "-b.", - afl->cpu_to_bind); + if (afl->afl_env.afl_try_affinity) { + + WARNF( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } else { + + FATAL( + "Could not bind to requested CPU %d! Make sure you passed a valid " + "-b.", + afl->cpu_to_bind); + + } } @@ -420,11 +431,14 @@ void bind_to_free_cpu(afl_state_t *afl) { "Uh-oh, looks like all %d CPU cores on your system are allocated to\n" " other instances of afl-fuzz (or similar CPU-locked tasks). " "Starting\n" - " another fuzzer on this machine is probably a bad plan, but if " - "you are\n" - " absolutely sure, you can set AFL_NO_AFFINITY and try again.\n", - afl->cpu_core_count); - FATAL("No more free CPU cores"); + " another fuzzer on this machine is probably a bad plan.\n" + "%s", + afl->cpu_core_count, + afl->afl_env.afl_try_affinity ? "" + : " If you are sure, you can set " + "AFL_NO_AFFINITY and try again.\n"); + + if (!afl->afl_env.afl_try_affinity) { FATAL("No more free CPU cores"); } } diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 046d17d6..0658070e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -202,6 +202,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_no_affinity = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_TRY_AFFINITY", + + afl_environment_variable_len)) { + + afl->afl_env.afl_try_affinity = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_SKIP_CRASHES", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 3b6ac5e2..bb970e5f 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -220,6 +220,7 @@ static void usage(u8 *argv0, int more_help) { " then they are randomly selected instead all of them being\n" " used. Defaults to 200.\n" "AFL_NO_AFFINITY: do not check for an unused cpu core to use for fuzzing\n" + "AFL_TRY_AFFINITY: try to bind to an unused core, but don't fail if unsuccessful\n" "AFL_NO_ARITH: skip arithmetic mutations in deterministic stage\n" "AFL_NO_AUTODICT: do not load an offered auto dictionary compiled into a target\n" "AFL_NO_CPU_RED: avoid red color for showing very high cpu usage\n" -- cgit 1.4.1 From ad3dba047f5186b3b0941d33f0cd37e9ac218069 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 25 May 2021 21:52:11 +0200 Subject: Typo --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index bbe55e3e..f8831ff1 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,7 +35,7 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated + - when AFL_FAST_CAL is set a variable path will now be calibrated 8 times instead of 40 - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails -- cgit 1.4.1 From 3b93729213de46a3008709bd8170d5593394d8cb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 22:04:25 +0200 Subject: tweaks --- docs/Changelog.md | 4 ++-- docs/custom_mutators.md | 3 +++ src/afl-fuzz-python.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index f8831ff1..175c6c43 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,8 +35,8 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will now be calibrated - 8 times instead of 40 + - when AFL_FAST_CAL is set a variable path will no be calibrated + 8 times instead of originally 40. Long calibration is now 20. - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails - afl-cc: diff --git a/docs/custom_mutators.md b/docs/custom_mutators.md index 9d5381e8..3e3ae01d 100644 --- a/docs/custom_mutators.md +++ b/docs/custom_mutators.md @@ -92,6 +92,9 @@ def queue_new_entry(filename_new_queue, filename_orig_queue): def introspection(): return string + +def deinit(): # optional for Python + pass ``` ### Custom Mutation diff --git a/src/afl-fuzz-python.c b/src/afl-fuzz-python.c index 8760194c..3aa97635 100644 --- a/src/afl-fuzz-python.c +++ b/src/afl-fuzz-python.c @@ -212,7 +212,7 @@ static py_mutator_t *init_py_module(afl_state_t *afl, u8 *module_name) { PyObject_GetAttrString(py_module, "introspection"); py_functions[PY_FUNC_DEINIT] = PyObject_GetAttrString(py_module, "deinit"); if (!py_functions[PY_FUNC_DEINIT]) - FATAL("deinit function not found in python module"); + WARNF("deinit function not found in python module"); for (py_idx = 0; py_idx < PY_FUNC_COUNT; ++py_idx) { -- cgit 1.4.1 From a5e551ab917cef708363483070eb62c55897cf3b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 25 May 2021 23:49:14 +0200 Subject: typos --- docs/Changelog.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 175c6c43..594637fb 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,7 +35,7 @@ sending a mail to . afl++ ignores these and uses them for splicing instead. - added AFL_EXIT_ON_TIME env that will make afl-fuzz exit fuzzing after no new paths have been found for n seconds - - when AFL_FAST_CAL is set a variable path will no be calibrated + - when AFL_FAST_CAL is set a variable path will now be calibrated 8 times instead of originally 40. Long calibration is now 20. - added AFL_TRY_AFFINITY to try to bind to CPUs but don't error if it fails @@ -57,7 +57,8 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename + - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the + current filename - afl-showmap/cmin will now process queue items in alphabetical order ### Version ++3.12c (release) -- cgit 1.4.1 From 8e86f7ad803e571bcd275d2aca597997ab0e4d2c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 28 May 2021 13:35:05 +0200 Subject: add --afl-noopt to afl-cc --- docs/Changelog.md | 1 + src/afl-cc.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 594637fb..298a3998 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -46,6 +46,7 @@ sending a mail to . - Removed InsTrim instrumentation as it is not as good as PCGUARD - Removed automatic linking with -lc++ for LTO mode - Fixed a crash in llvm dict2file when a strncmp length was -1 + - added --afl-noopt support - utils/aflpp_driver: - aflpp_qemu_driver_hook fixed to work with qemu_mode - aflpp_driver now compiled with -fPIC diff --git a/src/afl-cc.c b/src/afl-cc.c index ebe11525..8af8e7b0 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1224,6 +1224,14 @@ int main(int argc, char **argv, char **envp) { if (strncmp(argv[i], "--afl", 5) == 0) { + if (!strcmp(argv[i], "--afl_noopt") || !strcmp(argv[i], "--afl-noopt")) { + + passthrough = 1; + argv[i] = "-g"; // we have to overwrite it, -g is always good + continue; + + } + if (compiler_mode) WARNF( "--afl-... compiler mode supersedes the AFL_CC_COMPILER and " @@ -1821,6 +1829,12 @@ int main(int argc, char **argv, char **envp) { "If anything fails - be sure to read README.lto.md!\n"); #endif + SAYF( + "\nYou can supply --afl-noopt to not instrument, like AFL_NOOPT. " + "(this is helpful\n" + "in some build systems if you do not want to instrument " + "everything.\n"); + } SAYF( -- cgit 1.4.1 From eb74a7a8004e8281cda62525bbc1f3bbe7f5d9da Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 30 May 2021 12:43:30 +0200 Subject: add documentation for AFL_LLVM_THREADSAFE_INST --- docs/Changelog.md | 1 + docs/env_variables.md | 5 +++++ instrumentation/README.llvm.md | 4 ++++ instrumentation/README.neverzero.md | 5 +++++ src/afl-cc.c | 1 + 5 files changed, 16 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9c9a3976..d8e96bf3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -35,6 +35,7 @@ sending a mail to . - Removed automatic linking with -lc++ for LTO mode - utils/aflpp_driver/aflpp_qemu_driver_hook fixed to work with qemu mode - add -d (add dead fuzzer stats) to afl-whatsup + - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) ### Version ++3.12c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index 0100ffac..d9a774aa 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,6 +231,11 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. +### Thread safe instrumentation counters (in mode LLVM CLASSIC) + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe counters. + The overhead is a bit higher compared to the older non-thread safe case. + `AFL_LLVM_NOT_ZERO` and `AFL_LLVM_SKIP_NEVERZERO` are supported (see below). + ### NOT_ZERO - Setting `AFL_LLVM_NOT_ZERO=1` during compilation will use counters diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index adce6c1d..a9d51829 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,6 +144,10 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) +Support for thread safe counters has been added for mode LLVM CLASSIC. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in +multi threaded apps for a slightly higher instrumentation overhead. + ## 4) Snapshot feature To speed up fuzzing you can use a linux loadable kernel module which enables diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md index 49104e00..06334eab 100644 --- a/instrumentation/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -33,3 +33,8 @@ AFL_LLVM_SKIP_NEVERZERO=1 ``` If the target does not have extensive loops or functions that are called a lot then this can give a small performance boost. + +Please note that the default counter implementations are not thread safe! + +Support for thread safe counters in mode LLVM CLASSIC can be activated with setting +`AFL_LLVM_THREADSAFE_INST=1`. \ No newline at end of file diff --git a/src/afl-cc.c b/src/afl-cc.c index 1f89bac5..132f5f83 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1757,6 +1757,7 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters\n" COUNTER_BEHAVIOUR -- cgit 1.4.1 From 76653544056ce2334b6523252e91a8f8a6ac9dcb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 10:13:16 +0200 Subject: threadsafe doc fixes, code format --- README.md | 3 +- docs/Changelog.md | 3 +- docs/env_variables.md | 9 +- frida_mode/src/instrument/instrument_debug.c | 2 +- frida_mode/src/stats/stats.c | 4 +- instrumentation/README.llvm.md | 7 +- instrumentation/SanitizerCoverageLTO.so.cc | 7 +- instrumentation/SanitizerCoveragePCGUARD.so.cc | 6 +- instrumentation/afl-llvm-lto-instrumentation.so.cc | 11 +- instrumentation/afl-llvm-pass.so.cc | 116 +++++++++++++-------- qemu_mode/libqasan/libqasan.c | 5 +- src/afl-cc.c | 3 +- src/afl-fuzz-one.c | 1 + src/afl-fuzz.c | 7 +- 14 files changed, 106 insertions(+), 78 deletions(-) (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index 69e2d14a..c04dba98 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ behaviours and defaults: | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| + | Threadsafe counters | | x(3) | | | | | | NeverZero | x86[_64]| x(1) | x | x | x | x | | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | @@ -104,7 +105,7 @@ behaviours and defaults: 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin - 3. (currently unassigned) + 3. with `AFL_LLVM_THREADSAFE_INST`, disables NeverZero 4. with pcguard mode and LTO mode for LLVM 11 and newer 5. upcoming, development in the branch 6. not compatible with LTO instrumentation and needs at least LLVM v4.1 diff --git a/docs/Changelog.md b/docs/Changelog.md index d8ffe498..29ea918b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -41,6 +41,8 @@ sending a mail to . it fails - afl-cc: - We do not support llvm versions prior 6.0 anymore + - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`), + note that this disables never zero counters. - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD @@ -58,7 +60,6 @@ sending a mail to . MacOS shared memory - updated the grammar custom mutator to the newest version - add -d (add dead fuzzer stats) to afl-whatsup - - add thread safe counters for LLVM CLASSIC (set AFL_LLVM_THREADSAFE_INST) - added AFL_PRINT_FILENAMES to afl-showmap/cmin to print the current filename - afl-showmap/cmin will now process queue items in alphabetical order diff --git a/docs/env_variables.md b/docs/env_variables.md index b4b866ab..38a67bc7 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -231,10 +231,11 @@ Then there are a few specific features that are only available in instrumentatio See [instrumentation/README.instrument_list.md](../instrumentation/README.instrument_list.md) for more information. -### Thread safe instrumentation counters (in mode LLVM CLASSIC) - - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread safe counters. - The overhead is a bit higher compared to the older non-thread safe case. - `AFL_LLVM_NOT_ZERO` and `AFL_LLVM_SKIP_NEVERZERO` are supported (see below). +### Thread safe instrumentation counters (in all modes) + + - Setting `AFL_LLVM_THREADSAFE_INST` will inject code that implements thread + safe counters. The overhead is a little bit higher compared to the older + non-thread safe case. Note that this disables neverzero (see below). ### NOT_ZERO diff --git a/frida_mode/src/instrument/instrument_debug.c b/frida_mode/src/instrument/instrument_debug.c index be72ef89..f8c1df77 100644 --- a/frida_mode/src/instrument/instrument_debug.c +++ b/frida_mode/src/instrument/instrument_debug.c @@ -17,7 +17,7 @@ static void instrument_debug(char *format, ...) { va_list ap; char buffer[4096] = {0}; int ret; - int len; + int len; va_start(ap, format); ret = vsnprintf(buffer, sizeof(buffer) - 1, format, ap); diff --git a/frida_mode/src/stats/stats.c b/frida_mode/src/stats/stats.c index 890a8d6b..662fb6d5 100644 --- a/frida_mode/src/stats/stats.c +++ b/frida_mode/src/stats/stats.c @@ -96,10 +96,10 @@ void stats_init(void) { void stats_vprint(int fd, char *format, va_list ap) { char buffer[4096] = {0}; - int ret; + int ret; int len; - if(vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } + if (vsnprintf(buffer, sizeof(buffer) - 1, format, ap) < 0) { return; } len = strnlen(buffer, sizeof(buffer)); IGNORED_RETURN(write(fd, buffer, len)); diff --git a/instrumentation/README.llvm.md b/instrumentation/README.llvm.md index 02722588..8ce5afb9 100644 --- a/instrumentation/README.llvm.md +++ b/instrumentation/README.llvm.md @@ -144,9 +144,10 @@ is not optimal and was only fixed in llvm 9. You can set this with AFL_LLVM_NOT_ZERO=1 See [README.neverzero.md](README.neverzero.md) -Support for thread safe counters has been added for mode LLVM CLASSIC. -Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision in -multi threaded apps for a slightly higher instrumentation overhead. +Support for thread safe counters has been added for all modes. +Activate it with `AFL_LLVM_THREADSAFE_INST=1`. The tradeoff is better precision +in multi threaded apps for a slightly higher instrumentation overhead. +This also disables the nozero counter default for performance reasons. ## 4) Snapshot feature diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 58969e18..20f1856e 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1497,14 +1497,12 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ - if (use_threadsafe_counters) { /* Atomic */ + if (use_threadsafe_counters) { /* Atomic */ IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); - } - else - { + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(Mo->getMDKindID("nosanitize"), @@ -1524,6 +1522,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); } + // done :) inst++; diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index dbddad0a..4a8c9e28 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1069,16 +1069,14 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, /* Load counter for CurLoc */ - Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); + Value *MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); if (use_threadsafe_counters) { IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); - } - else - { + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); /* Update bitmap */ diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index b5fdb3d6..fe43fbe5 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -93,8 +93,8 @@ class AFLLTOPass : public ModulePass { uint32_t function_minimum_size = 1; uint32_t inst_blocks = 0, inst_funcs = 0, total_instr = 0; unsigned long long int map_addr = 0x10000; - const char *skip_nozero = NULL; - const char *use_threadsafe_counters = nullptr; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; }; @@ -843,9 +843,12 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ if (use_threadsafe_counters) { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } else { + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); @@ -861,7 +864,9 @@ bool AFLLTOPass::runOnModule(Module &M) { } IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + ->setMetadata(M.getMDKindID("nosanitize"), + MDNode::get(C, None)); + } // done :) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index fe9e2e40..62f8b2ed 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -81,12 +81,12 @@ class AFLCoverage : public ModulePass { bool runOnModule(Module &M) override; protected: - uint32_t ngram_size = 0; - uint32_t ctx_k = 0; - uint32_t map_size = MAP_SIZE; - uint32_t function_minimum_size = 1; - const char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; - const char * use_threadsafe_counters = nullptr; + uint32_t ngram_size = 0; + uint32_t ctx_k = 0; + uint32_t map_size = MAP_SIZE; + uint32_t function_minimum_size = 1; + const char *ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; }; @@ -188,18 +188,30 @@ bool AFLCoverage::runOnModule(Module &M) { if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { if (use_threadsafe_counters) { - if (!getenv("AFL_LLVM_NOT_ZERO")) { - skip_nozero = "1"; - SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); - } - else { - SAYF(cCYA "afl-llvm-pass" VERSION cRST - " using thread safe not-zero-counters\n"); - } - } - else - { - SAYF(cCYA "afl-llvm-pass" VERSION cRST " using non-thread safe instrumentation\n"); + + // disabled unless there is support for other modules as well + // (increases documentation complexity) + /* if (!getenv("AFL_LLVM_NOT_ZERO")) { */ + + skip_nozero = "1"; + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using thread safe counters\n"); + + /* + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using thread safe not-zero-counters\n"); + + } + + */ + + } else { + + SAYF(cCYA "afl-llvm-pass" VERSION cRST + " using non-thread safe instrumentation\n"); + } } @@ -649,44 +661,44 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ + if (use_threadsafe_counters) { /* Atomic */ - if (use_threadsafe_counters) {/* Atomic */ - - #if LLVM_VERSION_MAJOR < 9 +#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 - #else + NULL) { // with llvm 9 we make this the default as the bug in llvm + // is then fixed +#else if (!skip_nozero) { - #endif +#endif // register MapPtrIdx in a todo list todo.push_back(MapPtrIdx); - } - else - { + } else { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } - } - else - { + + } else { LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); Value *Incr = IRB.CreateAdd(Counter, One); - #if LLVM_VERSION_MAJOR < 9 +#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 - #else + NULL) { // with llvm 9 we make this the default as the bug in llvm + // is then fixed +#else if (!skip_nozero) { - #endif +#endif /* hexcoder: Realize a counter that skips zero during overflow. - * Once this counter reaches its maximum value, it next increments to 1 + * Once this counter reaches its maximum value, it next increments to + * 1 * * Instead of * Counter + 1 -> Counter @@ -705,7 +717,7 @@ bool AFLCoverage::runOnModule(Module &M) { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - } /* non atomic case */ + } /* non atomic case */ /* Update prev_loc history vector (by placing cur_loc at the head of the vector and shuffle the other elements back by one) */ @@ -762,16 +774,19 @@ bool AFLCoverage::runOnModule(Module &M) { } - if (use_threadsafe_counters) { /*Atomic NeverZero */ + if (use_threadsafe_counters) { /*Atomic NeverZero */ // handle the list of registered blocks to instrument for (auto val : todo) { - /* hexcoder: Realize a thread-safe counter that skips zero during overflow. Once this counter reaches its maximum value, it next increments to 1 - * - * Instead of - * Counter + 1 -> Counter - * we inject now this - * Counter + 1 -> {Counter, OverflowFlag} - * Counter + OverflowFlag -> Counter + + /* hexcoder: Realize a thread-safe counter that skips zero during + * overflow. Once this counter reaches its maximum value, it next + * increments to 1 + * + * Instead of + * Counter + 1 -> Counter + * we inject now this + * Counter + 1 -> {Counter, OverflowFlag} + * Counter + OverflowFlag -> Counter */ /* equivalent c code looks like this @@ -781,12 +796,19 @@ bool AFLCoverage::runOnModule(Module &M) { int old = atomic_load_explicit(&Counter, memory_order_relaxed); int new; do { + if (old == 255) { + new = 1; + } else { + new = old + 1; + } + } while (!atomic_compare_exchange_weak_explicit(&Counter, &old, new, + memory_order_relaxed, memory_order_relaxed)); */ @@ -805,7 +827,8 @@ bool AFLCoverage::runOnModule(Module &M) { BasicBlock *BB = IRB.GetInsertBlock(); // insert a basic block with the corpus of a do while loop - // the calculation may need to repeat, if atomic compare_exchange is not successful + // the calculation may need to repeat, if atomic compare_exchange is not + // successful BasicBlock::iterator it(*Counter); it++; // split after load counter @@ -857,6 +880,7 @@ bool AFLCoverage::runOnModule(Module &M) { // if the cmpXchg was not successful, retry IRB.CreateCondBr(Success, end_bb, do_while_bb); + } } diff --git a/qemu_mode/libqasan/libqasan.c b/qemu_mode/libqasan/libqasan.c index d4742e3e..6ea24f08 100644 --- a/qemu_mode/libqasan/libqasan.c +++ b/qemu_mode/libqasan/libqasan.c @@ -69,9 +69,8 @@ __attribute__((constructor)) void __libqasan_init() { __libqasan_is_initialized = 1; __libqasan_init_hooks(); - - if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) - __libqasan_hotpatch(); + + if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); if (getenv("AFL_INST_LIBS") || getenv("QASAN_HOTPACH")) __libqasan_hotpatch(); diff --git a/src/afl-cc.c b/src/afl-cc.c index 6be6e165..486f7468 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1777,7 +1777,8 @@ int main(int argc, char **argv, char **envp) { SAYF( "\nLLVM/LTO/afl-clang-fast/afl-clang-lto specific environment " "variables:\n" - " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters\n" + " AFL_LLVM_THREADSAFE_INST: instrument with thread safe counters, " + "disables neverzero\n" COUNTER_BEHAVIOUR diff --git a/src/afl-fuzz-one.c b/src/afl-fuzz-one.c index 4a3e7f33..c3ce2edd 100644 --- a/src/afl-fuzz-one.c +++ b/src/afl-fuzz-one.c @@ -561,6 +561,7 @@ u8 fuzz_one_original(afl_state_t *afl) { if (afl->cmplog_lvl == 3 || (afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) || + afl->queue_cur->favored || !(afl->fsrv.total_execs % afl->queued_paths) || get_cur_time() - afl->last_path_time > 300000) { // 300 seconds diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index a3a623d9..5bdb4c8d 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -2066,13 +2066,10 @@ int main(int argc, char **argv_orig, char **envp) { break; case 4: afl->expand_havoc = 5; - if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = 3; + // if (afl->cmplog_lvl && afl->cmplog_lvl < 3) afl->cmplog_lvl = + // 3; break; case 5: - // if not in sync mode, enable deterministic mode? - // if (!afl->sync_id) afl->skip_deterministic = 0; - afl->expand_havoc = 6; - case 6: // nothing else currently break; -- cgit 1.4.1 From 5b5dff4584f0efa2c02db7d75ebab7e31c253789 Mon Sep 17 00:00:00 2001 From: hexcoder Date: Tue, 1 Jun 2021 10:36:18 +0200 Subject: Wording: "never zero" -> NeverZero --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29ea918b..e7344761 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -42,7 +42,7 @@ sending a mail to . - afl-cc: - We do not support llvm versions prior 6.0 anymore - added thread safe counters to all modes (`AFL_LLVM_THREADSAFE_INST`), - note that this disables never zero counters. + note that this disables NeverZero counters. - Fix for -pie compiled binaries with default afl-clang-fast PCGUARD - Leak Sanitizer (AFL_USE_LSAN) added by Joshua Rogers, thanks! - Removed InsTrim instrumentation as it is not as good as PCGUARD -- cgit 1.4.1 From 17e904eedf025e870c79cd0dcc037282e1cce1d7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 10:40:25 +0200 Subject: fix afl_custom_post_process with multiple custom mutators --- docs/Changelog.md | 9 +++++---- src/afl-fuzz-run.c | 30 ++++++++++++------------------ 2 files changed, 17 insertions(+), 22 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index e7344761..09e46fb6 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -22,13 +22,14 @@ sending a mail to . to allow replay of non-reproducable crashes, see AFL_PERSISTENT_RECORD in config.h and docs/envs.h - fixed a bug when trimming for stdin targets - - default cmplog level (-l) is now 2, better efficiency. - - cmplog level 3 (-l 3) now performs redqueen on everything. - use with care. - - better fuzzing strategy yields for enabled options + - cmplog -l: default cmplog level is now 2, better efficiency. + level 3 now performs redqueen on everything. use with care. + - better fuzzing strategy yield display for enabled options - ensure one fuzzer sync per cycle - fix afl_custom_queue_new_entry original file name when syncing from fuzzers + - fixed a crash when more than one custom mutator was used together + with afl_custom_post_process - on a crashing seed potentially the wrong input was disabled - added AFL_EXIT_ON_SEED_ISSUES env that will exit if a seed in -i dir crashes the target or results in a timeout. By default diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 5a481639..7df4c625 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -107,27 +107,21 @@ write_to_testcase(afl_state_t *afl, void *mem, u32 len) { new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - } - - new_mem = new_buf; - - }); + if (unlikely(!new_buf && new_size <= 0)) { - if (unlikely(!new_buf && (new_size <= 0))) { - - FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); + FATAL("Custom_post_process failed (ret: %lu)", + (long unsigned)new_size); - } else if (likely(new_buf)) { + } - /* everything as planned. use the new data. */ - afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); + new_mem = new_buf; - } else { + } - /* custom mutators do not has a custom_post_process function */ - afl_fsrv_write_to_testcase(&afl->fsrv, mem, len); + }); - } + /* everything as planned. use the potentially new data. */ + afl_fsrv_write_to_testcase(&afl->fsrv, new_buf, new_size); } else { @@ -188,16 +182,16 @@ static void write_with_gap(afl_state_t *afl, u8 *mem, u32 len, u32 skip_at, new_size = el->afl_custom_post_process(el->data, new_mem, new_size, &new_buf); - if (unlikely(!new_buf || (new_size <= 0))) { + if (unlikely(!new_buf || new_size <= 0)) { FATAL("Custom_post_process failed (ret: %lu)", (long unsigned)new_size); } - } + new_mem = new_buf; - new_mem = new_buf; + } }); -- cgit 1.4.1 From f9ca2cf98938ae382d0affc47dbbc78d7291708b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 12:15:14 +0200 Subject: v3.13c release --- README.md | 4 ++-- docs/Changelog.md | 2 +- include/config.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index c04dba98..ba612edb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AFL++ Logo - Release Version: [3.12c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.13a + Github Version: 3.14a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/docs/Changelog.md b/docs/Changelog.md index 09e46fb6..1887c099 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,7 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++3.13a (development) +### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, it currently supports persistent mode and cmplog. diff --git a/include/config.h b/include/config.h index 80cdb684..a1fdd789 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13a" +#define VERSION "++3.13c" /****************************************************** * * -- cgit 1.4.1 From bdc7aa1a94b04de1e670f42eaa329bc18826cb9d Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 12:39:13 +0200 Subject: v3.14a init --- docs/Changelog.md | 4 ++++ include/config.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 1887c099..419d5a99 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,6 +8,10 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . +### Version ++3.14a (release) + - ... your pull request? + + ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, diff --git a/include/config.h b/include/config.h index a1fdd789..9d732e53 100644 --- a/include/config.h +++ b/include/config.h @@ -26,7 +26,7 @@ /* Version string: */ // c = release, a = volatile github dev, e = experimental branch -#define VERSION "++3.13c" +#define VERSION "++3.14a" /****************************************************** * * -- cgit 1.4.1 From bee3902062a7020218533476e006d9d438d75406 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 1 Jun 2021 18:44:52 +0200 Subject: add fix info --- docs/Changelog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 419d5a99..a49c0672 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,7 +9,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.14a (release) - - ... your pull request? + - Fix for llvm 13 ### Version ++3.13c (release) -- cgit 1.4.1 From a38aafc5d0cb9ccf75f99613f52fd0938f5f86c0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 2 Jun 2021 10:50:04 +0200 Subject: fix -F with slash option --- docs/Changelog.md | 3 +++ src/afl-fuzz-init.c | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index a49c0672..a4c6ac10 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -10,6 +10,9 @@ sending a mail to . ### Version ++3.14a (release) - Fix for llvm 13 + - afl-fuzz: + - fix -F when a '/' was part of the parameter + - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 88b5bc02..872e3a32 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -480,13 +480,22 @@ void read_foreign_testcases(afl_state_t *afl, int first) { for (iter = 0; iter < afl->foreign_sync_cnt; iter++) { - if (afl->foreign_syncs[iter].dir != NULL && - afl->foreign_syncs[iter].dir[0] != 0) { + if (afl->foreign_syncs[iter].dir && afl->foreign_syncs[iter].dir[0]) { if (first) ACTF("Scanning '%s'...", afl->foreign_syncs[iter].dir); time_t mtime_max = 0; - u8 * name = strrchr(afl->foreign_syncs[iter].dir, '/'); - if (!name) { name = afl->foreign_syncs[iter].dir; } + + u8 *name = strrchr(afl->foreign_syncs[iter].dir, '/'); + if (!name) { + + name = afl->foreign_syncs[iter].dir; + + } else { + + ++name; + + } + if (!strcmp(name, "queue") || !strcmp(name, "out") || !strcmp(name, "default")) { -- cgit 1.4.1 From a5ff9f1bebfc974a774bba896e51e18288f66c68 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 09:02:33 +0200 Subject: remove -D from -M --- docs/Changelog.md | 1 + src/afl-fuzz.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index a4c6ac10..b70ba022 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,6 +12,7 @@ sending a mail to . - Fix for llvm 13 - afl-fuzz: - fix -F when a '/' was part of the parameter + - removed implied -D determinstic from -M main - ensure afl-compiler-rt is built for gcc_module diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 196547f4..dc594b30 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -575,7 +575,6 @@ int main(int argc, char **argv_orig, char **envp) { } afl->sync_id = ck_strdup(optarg); - afl->skip_deterministic = 0; // force deterministic fuzzing afl->old_seed_selection = 1; // force old queue walking seed selection afl->disable_trim = 1; // disable trimming -- cgit 1.4.1 From 4bf08566caccc950e9281474153ee1e3b1984179 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 11:22:07 +0200 Subject: add changelog entry --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index b70ba022..3e79103a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,6 +13,8 @@ sending a mail to . - afl-fuzz: - fix -F when a '/' was part of the parameter - removed implied -D determinstic from -M main + - if the target becomes unavailable check out out/default/error.txt for + an indicator why - ensure afl-compiler-rt is built for gcc_module -- cgit 1.4.1 From c69edc2b3cc6c9d58c1d10385555817d6d1c43b0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 11:23:58 +0200 Subject: add changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 3e79103a..a2c523b0 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,8 @@ sending a mail to . - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why + - afl-cc + - support partial linking - ensure afl-compiler-rt is built for gcc_module -- cgit 1.4.1 From 63ee9df54f3c9db8ecbb0fb6186ea912200d9126 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 20:49:23 +0200 Subject: Forkserver for afl-analyze (#963) * afl-analyze forkserver * added missing vars to forkserver * synchronized a bit more with afl-tmin * more debugging, runs now, but need to suppress target output * fix dev/null setting * afl-analyze info: Co-authored-by: hexcoder- --- GNUmakefile | 4 +- docs/Changelog.md | 3 +- src/afl-analyze.c | 235 +++++++++++++++++++----------------------------------- 3 files changed, 84 insertions(+), 158 deletions(-) (limited to 'docs/Changelog.md') diff --git a/GNUmakefile b/GNUmakefile index 6df7ea1d..bd206af0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -436,8 +436,8 @@ afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-fork afl-tmin: src/afl-tmin.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(LDFLAGS) -afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o $(COMM_HDR) | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o -o $@ $(LDFLAGS) +afl-analyze: src/afl-analyze.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o $(COMM_HDR) | test_x86 + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o src/afl-sharedmem.o src/afl-performance.o src/afl-forkserver.o -o $@ $(LDFLAGS) afl-gotcpu: src/afl-gotcpu.c src/afl-common.o $(COMM_HDR) | test_x86 $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) src/$@.c src/afl-common.o -o $@ $(LDFLAGS) diff --git a/docs/Changelog.md b/docs/Changelog.md index a2c523b0..a8ed4d72 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -18,8 +18,7 @@ sending a mail to . - afl-cc - support partial linking - ensure afl-compiler-rt is built for gcc_module - - + - afl-analyze now uses the forkserver for increased performance ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, diff --git a/src/afl-analyze.c b/src/afl-analyze.c index d43278b9..606254d9 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -55,12 +55,7 @@ #include #include -static s32 child_pid; /* PID of the tested program */ - -static u8 *trace_bits; /* SHM with instrumentation bitmap */ - -static u8 *in_file, /* Analyzer input test case */ - *prog_in; /* Targeted program input file */ +static u8 *in_file; /* Analyzer input test case */ static u8 *in_data; /* Input data for analysis */ @@ -73,20 +68,19 @@ static u64 orig_cksum; /* Original checksum */ static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */ -static s32 dev_null_fd = -1; /* FD to /dev/null */ - static bool edges_only, /* Ignore hit counts? */ use_hex_offsets, /* Show hex offsets? */ use_stdin = true; /* Use stdin for program input? */ -static volatile u8 stop_soon, /* Ctrl-C pressed? */ - child_timed_out; /* Child timed out? */ +static volatile u8 stop_soon; /* Ctrl-C pressed? */ static u8 *target_path; static u8 frida_mode; static u8 qemu_mode; static u32 map_size = MAP_SIZE; +static afl_forkserver_t fsrv = {0}; /* The forkserver */ + /* Constants used for describing byte behavior. */ #define RESP_NONE 0x00 /* Changing byte is a no-op. */ @@ -156,7 +150,7 @@ static void classify_counts(u8 *mem) { static inline u8 anything_set(void) { - u32 *ptr = (u32 *)trace_bits; + u32 *ptr = (u32 *)fsrv.trace_bits; u32 i = (map_size >> 2); while (i--) { @@ -173,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(prog_in); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -205,128 +199,29 @@ static void read_initial_file(void) { } -/* Write output file. */ - -static s32 write_to_file(u8 *path, u8 *mem, u32 len) { - - s32 ret; - - unlink(path); /* Ignore errors */ - - ret = open(path, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); - - if (ret < 0) { PFATAL("Unable to create '%s'", path); } - - ck_write(ret, mem, len, path); - - lseek(ret, 0, SEEK_SET); - - return ret; - -} - -/* Handle timeout signal. */ - -static void handle_timeout(int sig) { - - (void)sig; - - child_timed_out = 1; - - if (child_pid > 0) kill(child_pid, SIGKILL); - -} - /* Execute target application. Returns exec checksum, or 0 if program times out. */ -static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { - - static struct itimerval it; - int status = 0; - - s32 prog_in_fd; - u64 cksum; - - memset(trace_bits, 0, map_size); - MEM_BARRIER(); - - prog_in_fd = write_to_file(prog_in, mem, len); - - child_pid = fork(); - - if (child_pid < 0) { PFATAL("fork() failed"); } - - if (!child_pid) { - - struct rlimit r; - - if (dup2(use_stdin ? prog_in_fd : dev_null_fd, 0) < 0 || - dup2(dev_null_fd, 1) < 0 || dup2(dev_null_fd, 2) < 0) { - - *(u32 *)trace_bits = EXEC_FAIL_SIG; - PFATAL("dup2() failed"); - - } - - close(dev_null_fd); - close(prog_in_fd); - - if (mem_limit) { +static u32 analyze_run_target(u8 *mem, u32 len, u8 first_run) { - r.rlim_max = r.rlim_cur = ((rlim_t)mem_limit) << 20; + afl_fsrv_write_to_testcase(&fsrv, mem, len); + fsrv_run_result_t ret = afl_fsrv_run_target(&fsrv, exec_tmout, &stop_soon); -#ifdef RLIMIT_AS + if (ret == FSRV_RUN_ERROR) { - setrlimit(RLIMIT_AS, &r); /* Ignore errors */ + FATAL("Error in forkserver"); -#else - - setrlimit(RLIMIT_DATA, &r); /* Ignore errors */ - -#endif /* ^RLIMIT_AS */ - - } + } else if (ret == FSRV_RUN_NOINST) { - r.rlim_max = r.rlim_cur = 0; - setrlimit(RLIMIT_CORE, &r); /* Ignore errors */ + FATAL("Target not instrumented"); - execv(target_path, argv); + } else if (ret == FSRV_RUN_NOBITS) { - *(u32 *)trace_bits = EXEC_FAIL_SIG; - exit(0); + FATAL("Failed to run target"); } - close(prog_in_fd); - - /* Configure timeout, wait for child, cancel timeout. */ - - child_timed_out = 0; - it.it_value.tv_sec = (exec_tmout / 1000); - it.it_value.tv_usec = (exec_tmout % 1000) * 1000; - - setitimer(ITIMER_REAL, &it, NULL); - - if (waitpid(child_pid, &status, 0) <= 0) { FATAL("waitpid() failed"); } - - child_pid = 0; - it.it_value.tv_sec = 0; - it.it_value.tv_usec = 0; - - setitimer(ITIMER_REAL, &it, NULL); - - MEM_BARRIER(); - - /* Clean up bitmap, analyze exit condition, etc. */ - - if (*(u32 *)trace_bits == EXEC_FAIL_SIG) { - - FATAL("Unable to execute '%s'", argv[0]); - - } - - classify_counts(trace_bits); + classify_counts(fsrv.trace_bits); total_execs++; if (stop_soon) { @@ -338,21 +233,19 @@ static u32 analyze_run_target(char **argv, u8 *mem, u32 len, u8 first_run) { /* Always discard inputs that time out. */ - if (child_timed_out) { + if (fsrv.last_run_timed_out) { exec_hangs++; return 0; } - cksum = hash64(trace_bits, map_size, HASH_CONST); + u64 cksum = hash64(fsrv.trace_bits, fsrv.map_size, HASH_CONST); - /* We don't actually care if the target is crashing or not, - except that when it does, the checksum should be different. */ + if (ret == FSRV_RUN_CRASH) { - if (WIFSIGNALED(status) || - (WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) || - (WIFEXITED(status) && WEXITSTATUS(status))) { + /* We don't actually care if the target is crashing or not, + except that when it does, the checksum should be different. */ cksum ^= 0xffffffff; @@ -616,7 +509,7 @@ static void dump_hex(u32 len, u8 *b_data) { /* Actually analyze! */ -static void analyze(char **argv) { +static void analyze() { u32 i; u32 boring_len = 0, prev_xff = 0, prev_x01 = 0, prev_s10 = 0, prev_a10 = 0; @@ -642,16 +535,16 @@ static void analyze(char **argv) { code. */ in_data[i] ^= 0xff; - xor_ff = analyze_run_target(argv, in_data, in_len, 0); + xor_ff = analyze_run_target(in_data, in_len, 0); in_data[i] ^= 0xfe; - xor_01 = analyze_run_target(argv, in_data, in_len, 0); + xor_01 = analyze_run_target(in_data, in_len, 0); in_data[i] = (in_data[i] ^ 0x01) - 0x10; - sub_10 = analyze_run_target(argv, in_data, in_len, 0); + sub_10 = analyze_run_target(in_data, in_len, 0); in_data[i] += 0x20; - add_10 = analyze_run_target(argv, in_data, in_len, 0); + add_10 = analyze_run_target(in_data, in_len, 0); in_data[i] -= 0x10; /* Classify current behavior. */ @@ -724,7 +617,7 @@ static void handle_stop_sig(int sig) { (void)sig; stop_soon = 1; - if (child_pid > 0) { kill(child_pid, SIGKILL); } + afl_fsrv_killall(); } @@ -736,10 +629,10 @@ static void set_up_environment(char **argv) { char *afl_preload; char *frida_afl_preload = NULL; - dev_null_fd = open("/dev/null", O_RDWR); - if (dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } + fsrv.dev_null_fd = open("/dev/null", O_RDWR); + if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } - if (!prog_in) { + if (!fsrv.out_file) { u8 *use_dir = "."; @@ -750,10 +643,15 @@ static void set_up_environment(char **argv) { } - prog_in = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } + unlink(fsrv.out_file); + fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + + if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } + /* Set sane defaults... */ x = get_afl_env("ASAN_OPTIONS"); @@ -916,11 +814,6 @@ static void setup_signal_handlers(void) { sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); - /* Exec timeout notifications. */ - - sa.sa_handler = handle_timeout; - sigaction(SIGALRM, &sa, NULL); - } /* Display usage hints. */ @@ -982,6 +875,8 @@ int main(int argc, char **argv_orig, char **envp) { SAYF(cCYA "afl-analyze" VERSION cRST " by Michal Zalewski\n"); + afl_fsrv_init(&fsrv); + while ((opt = getopt(argc, argv, "+i:f:m:t:eOQUWh")) > 0) { switch (opt) { @@ -994,9 +889,9 @@ int main(int argc, char **argv_orig, char **envp) { case 'f': - if (prog_in) { FATAL("Multiple -f options not supported"); } - use_stdin = 0; - prog_in = optarg; + if (fsrv.out_file) { FATAL("Multiple -f options not supported"); } + fsrv.use_stdin = 0; + fsrv.out_file = ck_strdup(optarg); break; case 'e': @@ -1017,6 +912,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!strcmp(optarg, "none")) { mem_limit = 0; + fsrv.mem_limit = 0; break; } @@ -1055,6 +951,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.mem_limit = mem_limit; + } break; @@ -1074,6 +972,8 @@ int main(int argc, char **argv_orig, char **envp) { } + fsrv.exec_tmout = exec_tmout; + break; case 'O': /* FRIDA mode */ @@ -1081,6 +981,7 @@ int main(int argc, char **argv_orig, char **envp) { if (frida_mode) { FATAL("Multiple -O options not supported"); } frida_mode = 1; + fsrv.frida_mode = frida_mode; break; @@ -1090,6 +991,8 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_QEMU; } qemu_mode = 1; + fsrv.mem_limit = mem_limit; + fsrv.qemu_mode = qemu_mode; break; case 'U': @@ -1098,6 +1001,7 @@ int main(int argc, char **argv_orig, char **envp) { if (!mem_limit_given) { mem_limit = MEM_LIMIT_UNICORN; } unicorn_mode = 1; + fsrv.mem_limit = mem_limit; break; case 'W': /* Wine+QEMU mode */ @@ -1107,6 +1011,8 @@ int main(int argc, char **argv_orig, char **envp) { use_wine = 1; if (!mem_limit_given) { mem_limit = 0; } + fsrv.qemu_mode = qemu_mode; + fsrv.mem_limit = mem_limit; break; @@ -1125,6 +1031,7 @@ int main(int argc, char **argv_orig, char **envp) { if (optind == argc || !in_file) { usage(argv[0]); } map_size = get_map_size(); + fsrv.map_size = map_size; use_hex_offsets = !!get_afl_env("AFL_ANALYZE_HEX"); @@ -1134,14 +1041,15 @@ int main(int argc, char **argv_orig, char **envp) { /* initialize cmplog_mode */ shm.cmplog_mode = 0; - trace_bits = afl_shm_init(&shm, map_size, 0); + atexit(at_exit_handler); setup_signal_handlers(); set_up_environment(argv); - target_path = find_binary(argv[optind]); - detect_file_args(argv + optind, prog_in, &use_stdin); + fsrv.target_path = find_binary(argv[optind]); + fsrv.trace_bits = afl_shm_init(&shm, map_size, 0); + detect_file_args(argv + optind, fsrv.out_file, &use_stdin); if (qemu_mode) { @@ -1165,14 +1073,31 @@ int main(int argc, char **argv_orig, char **envp) { SAYF("\n"); + if (getenv("AFL_FORKSRV_INIT_TMOUT")) { + + s32 forksrv_init_tmout = atoi(getenv("AFL_FORKSRV_INIT_TMOUT")); + if (forksrv_init_tmout < 1) { + + FATAL("Bad value specified for AFL_FORKSRV_INIT_TMOUT"); + + } + + fsrv.init_tmout = (u32)forksrv_init_tmout; + + } + + fsrv.kill_signal = + parse_afl_kill_signal_env(getenv("AFL_KILL_SIGNAL"), SIGKILL); + read_initial_file(); ACTF("Performing dry run (mem limit = %llu MB, timeout = %u ms%s)...", mem_limit, exec_tmout, edges_only ? ", edges only" : ""); - analyze_run_target(use_argv, in_data, in_len, 1); + afl_fsrv_start(&fsrv, use_argv, &stop_soon, false); + analyze_run_target(in_data, in_len, 1); - if (child_timed_out) { + if (fsrv.last_run_timed_out) { FATAL("Target binary times out (adjusting -t may help)."); @@ -1184,13 +1109,15 @@ int main(int argc, char **argv_orig, char **envp) { } - analyze(use_argv); + analyze(); OKF("We're done here. Have a nice day!\n"); - if (target_path) { ck_free(target_path); } - afl_shm_deinit(&shm); + afl_fsrv_deinit(&fsrv); + if (fsrv.target_path) { ck_free(fsrv.target_path); } + if (in_data) { ck_free(in_data); } + exit(0); -- cgit 1.4.1 From d64dd7a952de20b693ed1a44063d409a15bbff76 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 7 Jun 2021 22:37:06 +0200 Subject: proper newlines --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index a8ed4d72..103f5920 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,6 +19,8 @@ sending a mail to . - support partial linking - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance + + ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 - frida_mode - new mode that uses frida to fuzz binary-only targets, -- cgit 1.4.1 From fff8c5e0a855eb26408a555758ebe29044b047cd Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Tue, 8 Jun 2021 09:56:11 +0200 Subject: adapt docs to minimum LLVM version --- README.md | 4 ++-- docs/Changelog.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index 383d71c4..bc547b3c 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ behaviours and defaults: ## Important features of afl++ - afl++ supports llvm from 6.0 up to version 12, very fast binary fuzzing with QEMU 5.1 + afl++ supports llvm from 3.8 up to version 12, very fast binary fuzzing with QEMU 5.1 with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. @@ -296,7 +296,7 @@ anything below 9 is not recommended. | v +---------------------------------+ -| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +| clang/clang++ 3.8+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++) +---------------------------------+ see [instrumentation/README.llvm.md](instrumentation/README.llvm.md) | | if not, or if the target fails with LLVM afl-clang-fast/++ diff --git a/docs/Changelog.md b/docs/Changelog.md index 103f5920..6c851460 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,9 @@ sending a mail to . an indicator why - afl-cc - support partial linking + - We do support llvm versions from 3.8 again + - afl_analyze + - fix timeout handling and support forkserver - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance -- cgit 1.4.1 From a7340a1ac6c6165c8eb390a503758104c0d85bcb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 10 Jun 2021 10:25:37 +0200 Subject: fix AFL_CAL_FAST --- docs/Changelog.md | 1 + docs/env_variables.md | 4 +--- include/afl-fuzz.h | 4 +--- src/afl-analyze.c | 9 +++++---- src/afl-fuzz-run.c | 5 +++-- src/afl-fuzz-state.c | 9 +++++++-- src/afl-fuzz.c | 9 --------- 7 files changed, 18 insertions(+), 23 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 6c851460..29ef69f9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,7 @@ sending a mail to . - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why + - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - afl-cc - support partial linking - We do support llvm versions from 3.8 again diff --git a/docs/env_variables.md b/docs/env_variables.md index 38a67bc7..e058f377 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -108,9 +108,6 @@ make fairly broad use of environmental variables instead: - Setting `AFL_QUIET` will prevent afl-cc and afl-as banners from being displayed during compilation, in case you find them distracting. - - Setting `AFL_CAL_FAST` will speed up the initial calibration, if the - application is very slow. - ## 2) Settings for LLVM and LTO: afl-clang-fast / afl-clang-fast++ / afl-clang-lto / afl-clang-lto++ The native instrumentation helpers (instrumentation and gcc_plugin) accept a subset @@ -386,6 +383,7 @@ checks or alter some of the more exotic semantics of the tool: - `AFL_FAST_CAL` keeps the calibration stage about 2.5x faster (albeit less precise), which can help when starting a session against a slow target. + `AFL_CAL_FAST` works too. - The CPU widget shown at the bottom of the screen is fairly simplistic and may complain of high load prematurely, especially on systems with low core diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index 4aba3bdf..2920f905 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -478,9 +478,7 @@ typedef struct afl_state { u32 hang_tmout; /* Timeout used for hang det (ms) */ - u8 cal_cycles, /* Calibration cycles defaults */ - cal_cycles_long, /* Calibration cycles defaults */ - havoc_stack_pow2, /* HAVOC_STACK_POW2 */ + u8 havoc_stack_pow2, /* HAVOC_STACK_POW2 */ no_unlink, /* do not unlink cur_input */ debug, /* Debug mode */ custom_only, /* Custom mutator only mode */ diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 606254d9..dbf2920f 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -167,7 +167,7 @@ static inline u8 anything_set(void) { static void at_exit_handler(void) { - unlink(fsrv.out_file); /* Ignore errors */ + unlink(fsrv.out_file); /* Ignore errors */ } @@ -643,12 +643,14 @@ static void set_up_environment(char **argv) { } - fsrv.out_file = alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); + fsrv.out_file = + alloc_printf("%s/.afl-analyze-temp-%u", use_dir, (u32)getpid()); } unlink(fsrv.out_file); - fsrv.out_fd = open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); + fsrv.out_fd = + open(fsrv.out_file, O_RDWR | O_CREAT | O_EXCL, DEFAULT_PERMISSION); if (fsrv.out_fd < 0) { PFATAL("Unable to create '%s'", fsrv.out_file); } @@ -1118,7 +1120,6 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv.target_path) { ck_free(fsrv.target_path); } if (in_data) { ck_free(in_data); } - exit(0); } diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 493735ff..758bad25 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -314,7 +314,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, ++q->cal_failed; afl->stage_name = "calibration"; - afl->stage_max = afl->fast_cal ? 3 : CAL_CYCLES; + afl->stage_max = afl->afl_env.afl_cal_fast ? 3 : CAL_CYCLES; /* Make sure the forkserver is up before we do anything, and let's not count its spin-up time toward binary calibration. */ @@ -403,7 +403,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = afl->fast_cal ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = + afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 0658070e..b832c11e 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -96,8 +96,6 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->splicing_with = -1; /* Splicing with which test case? */ afl->cpu_to_bind = -1; afl->havoc_stack_pow2 = HAVOC_STACK_POW2; - afl->cal_cycles = CAL_CYCLES; - afl->cal_cycles_long = CAL_CYCLES_LONG; afl->hang_tmout = EXEC_TIMEOUT; afl->exit_on_time = 0; afl->stats_update_freq = 1; @@ -341,6 +339,13 @@ void read_afl_environment(afl_state_t *afl, char **envp) { afl->afl_env.afl_cal_fast = get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_FAST_CAL", + + afl_environment_variable_len)) { + + afl->afl_env.afl_cal_fast = + get_afl_env(afl_environment_variables[i]) ? 1 : 0; + } else if (!strncmp(env, "AFL_STATSD", afl_environment_variable_len)) { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 9a3780fb..e9a67ac5 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1276,7 +1276,6 @@ int main(int argc, char **argv_orig, char **envp) { if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; } if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } if (get_afl_env("AFL_SHUFFLE_QUEUE")) { afl->shuffle_queue = 1; } - if (get_afl_env("AFL_FAST_CAL")) { afl->fast_cal = 1; } if (get_afl_env("AFL_EXPAND_HAVOC_NOW")) { afl->expand_havoc = 1; } if (afl->afl_env.afl_autoresume) { @@ -1489,14 +1488,6 @@ int main(int argc, char **argv_orig, char **envp) { check_if_tty(afl); if (afl->afl_env.afl_force_ui) { afl->not_on_tty = 0; } - if (afl->afl_env.afl_cal_fast) { - - /* Use less calibration cycles, for slow applications */ - afl->cal_cycles = 3; - afl->cal_cycles_long = 5; - - } - if (afl->afl_env.afl_custom_mutator_only) { /* This ensures we don't proceed to havoc/splice */ -- cgit 1.4.1 From 63504f7b7e9f17145b63ba7d5a9e837e17ccb3a6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 10:44:06 +0200 Subject: fix cmplog screen update crash --- docs/Changelog.md | 3 +- src/afl-common.c | 2 ++ src/afl-fuzz-redqueen.c | 91 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 63 insertions(+), 33 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29ef69f9..97903c2a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -9,9 +9,9 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . ### Version ++3.14a (release) - - Fix for llvm 13 - afl-fuzz: - fix -F when a '/' was part of the parameter + - fixed a crash for cmplog for very slow inputs - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why @@ -21,6 +21,7 @@ sending a mail to . - We do support llvm versions from 3.8 again - afl_analyze - fix timeout handling and support forkserver + - Fix for llvm 13 - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance diff --git a/src/afl-common.c b/src/afl-common.c index c61ce3d8..9ca2b3e8 100644 --- a/src/afl-common.c +++ b/src/afl-common.c @@ -751,6 +751,8 @@ void read_bitmap(u8 *fname, u8 *map, size_t len) { } +/* Get unix time in milliseconds */ + u64 get_cur_time(void) { struct timeval tv; diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index b41ffa88..268f726c 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -252,7 +252,7 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, u64 start_time = get_cur_time(); #endif - u32 screen_update = 1000000 / afl->queue_cur->exec_us; + u32 screen_update; u64 orig_hit_cnt, new_hit_cnt, exec_cksum; orig_hit_cnt = afl->queued_paths + afl->unique_crashes; @@ -261,6 +261,24 @@ static u8 colorization(afl_state_t *afl, u8 *buf, u32 len, afl->stage_max = (len << 1); afl->stage_cur = 0; + if (likely(afl->queue_cur->exec_us)) { + + if (likely((100000 / 2) >= afl->queue_cur->exec_us)) { + + screen_update = 100000 / afl->queue_cur->exec_us; + + } else { + + screen_update = 1; + + } + + } else { + + screen_update = 100000; + + } + // in colorization we do not classify counts, hence we have to calculate // the original checksum. if (unlikely(get_exec_checksum(afl, buf, len, &exec_cksum))) { @@ -905,17 +923,16 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // test for arithmetic, eg. "if ((user_val - 0x1111) == 0x1234) ..." s64 diff = pattern - b_val; s64 o_diff = o_pattern - o_b_val; - /* - fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, - h->shape + 1, o_pattern, o_b_val, o_diff); - fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, - b_val, diff);*/ + /* fprintf(stderr, "DIFF1 idx=%03u shape=%02u %llx-%llx=%lx\n", idx, + h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, "DIFF1 %016llx %llx-%llx=%lx\n", repl, pattern, + b_val, diff); */ if (diff == o_diff && diff) { // this could be an arithmetic transformation u64 new_repl = (u64)((s64)repl - diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -935,15 +952,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, diff = pattern ^ b_val; s64 o_diff = o_pattern ^ o_b_val; - /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF2 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF2 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (diff == o_diff && diff) { // this could be a XOR transformation u64 new_repl = (u64)((s64)repl ^ diff); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -982,15 +1001,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF3 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF3 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl & (0x5f5f5f5f5f5f5f5f & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1029,15 +1050,17 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", - idx, h->shape + 1, o_pattern, o_b_val, o_diff); fprintf(stderr, - "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff);*/ + /* fprintf(stderr, "DIFF4 idx=%03u shape=%02u %llx-%llx=%lx\n", + idx, h->shape + 1, o_pattern, o_b_val, o_diff); + fprintf(stderr, + "DIFF4 %016llx %llx-%llx=%lx\n", repl, pattern, b_val, diff); + */ if (o_diff && diff) { // this could be a lower to upper u64 new_repl = (repl | (0x2020202020202020 & mask)); - // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); + // fprintf(stderr, "SAME DIFF %llx->%llx\n", repl, new_repl); if (unlikely(cmp_extend_encoding( afl, h, pattern, new_repl, o_pattern, repl, IS_TRANSFORM, idx, @@ -1383,7 +1406,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } - //#endif /* CMPLOG_SOLVE_ARITHMETIC + //#endif /* + // CMPLOG_SOLVE_ARITHMETIC return 0; @@ -2152,7 +2176,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, memcpy(buf + idx, tmp, i + 1); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, *status); + // fprintf(stderr, "RTN ATTEMPT tohex %u result %u\n", tohex, + // *status); } @@ -2235,7 +2260,8 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 *pattern, u8 *repl, for (j = 0; j <= i; j++) buf[idx + j] = repl[j] - arith_val[j]; if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, *status); + // fprintf(stderr, "RTN ATTEMPT arith %u result %u\n", arith, + // *status); } @@ -2328,16 +2354,17 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, /* struct cmp_header *hh = &afl->orig_cmp_map->headers[key]; - fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, h->id, - h->shape, h->attribute); for (j = 0; j < 8; j++) fprintf(stderr, "%02x", - o->v0[j]); fprintf(stderr, " v1="); for (j = 0; j < 8; j++) fprintf(stderr, - "%02x", o->v1[j]); fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u - o0=", hh->hits, hh->id, hh->shape, hh->attribute); for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v0[j]); - fprintf(stderr, " o1="); - for (j = 0; j < 8; j++) - fprintf(stderr, "%02x", orig_o->v1[j]); - fprintf(stderr, "\n"); + fprintf(stderr, "RTN N hits=%u id=%u shape=%u attr=%u v0=", h->hits, + h->id, h->shape, h->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v0[j]); + fprintf(stderr, " v1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", o->v1[j]); + fprintf(stderr, "\nRTN O hits=%u id=%u shape=%u attr=%u o0=", + hh->hits, hh->id, hh->shape, hh->attribute); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v0[j]); + fprintf(stderr, " o1="); + for (j = 0; j < 8; j++) fprintf(stderr, "%02x", orig_o->v1[j]); + fprintf(stderr, "\n"); */ t = taint; -- cgit 1.4.1 From 581593ccab9516fbe372355fdb06180a5357e813 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 11:05:57 +0200 Subject: code format --- docs/Changelog.md | 4 +- docs/FAQ.md | 21 ++++ instrumentation/split-compares-pass.so.cc | 184 +++++++++++++++++++++++++++++- 3 files changed, 206 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 97903c2a..0e2ce27d 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,11 +17,13 @@ sending a mail to . an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - afl-cc + - Update to COMPCOV/laf-intel that speeds up the instrumentation process + a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix for llvm 13 - support partial linking - We do support llvm versions from 3.8 again - afl_analyze - fix timeout handling and support forkserver - - Fix for llvm 13 - ensure afl-compiler-rt is built for gcc_module - afl-analyze now uses the forkserver for increased performance diff --git a/docs/FAQ.md b/docs/FAQ.md index 714d50eb..ab0abe6c 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -3,6 +3,7 @@ ## Contents * [What is the difference between afl and afl++?](#what-is-the-difference-between-afl-and-afl) + * [I got a weird compile error from clang](#i-got-a-weird-compile-error-from-clang) * [How to improve the fuzzing speed?](#how-to-improve-the-fuzzing-speed) * [How do I fuzz a network service?](#how-do-i-fuzz-a-network-service) * [How do I fuzz a GUI program?](#how-do-i-fuzz-a-gui-program) @@ -35,6 +36,26 @@ flexible and feature rich guided fuzzer available as open source. And in independent fuzzing benchmarks it is one of the best fuzzers available, e.g. [Fuzzbench Report](https://www.fuzzbench.com/reports/2020-08-03/index.html) +## I got a weird compile error from clang + +If you see this kind of error when trying to instrument a target with afl-cc/ +afl-clang-fast/afl-clang-lto: +``` +/prg/tmp/llvm-project/build/bin/clang-13: symbol lookup error: /usr/local/bin/../lib/afl//cmplog-instructions-pass.so: undefined symbol: _ZNK4llvm8TypeSizecvmEv +clang-13: error: unable to execute command: No such file or directory +clang-13: error: clang frontend command failed due to signal (use -v to see invocation) +clang version 13.0.0 (https://github.com/llvm/llvm-project 1d7cf550721c51030144f3cd295c5789d51c4aad) +Target: x86_64-unknown-linux-gnu +Thread model: posix +InstalledDir: /prg/tmp/llvm-project/build/bin +clang-13: note: diagnostic msg: +******************** +``` +Then this means that your OS updated the clang installation from an upgrade +package and because of that the afl++ llvm plugins do not match anymore. + +Solution: `git pull ; make clean install` of afl++ + ## How to improve the fuzzing speed? 1. Use [llvm_mode](docs/llvm_mode/README.md): afl-clang-lto (llvm >= 11) or afl-clang-fast (llvm >= 9 recommended) diff --git a/instrumentation/split-compares-pass.so.cc b/instrumentation/split-compares-pass.so.cc index 6eb9050c..10f86a66 100644 --- a/instrumentation/split-compares-pass.so.cc +++ b/instrumentation/split-compares-pass.so.cc @@ -54,20 +54,25 @@ using namespace llvm; namespace { class SplitComparesTransform : public ModulePass { + public: static char ID; SplitComparesTransform() : ModulePass(ID), enableFPSplit(0) { + initInstrumentList(); + } bool runOnModule(Module &M) override; #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { + #else const char *getPassName() const override { #endif return "AFL_SplitComparesTransform"; + } private: @@ -98,30 +103,47 @@ class SplitComparesTransform : public ModulePass { /// print an error to llvm's errs stream, but only if not ordered to be quiet void reportError(const StringRef msg, Instruction *I, Module &M) { + if (!be_quiet) { + errs() << "[AFL++ SplitComparesTransform] ERROR: " << msg << "\n"; if (debug) { + if (I) { + errs() << "Instruction = " << *I << "\n"; if (auto BB = I->getParent()) { + if (auto F = BB->getParent()) { + if (F->hasName()) { + errs() << "|-> in function " << F->getName() << " "; + } + } + } + } + auto n = M.getName(); if (n.size() > 0) { errs() << "in module " << n << "\n"; } + } + } + } bool isSupportedBitWidth(unsigned bitw) { + // IDK whether the icmp code works on other bitwidths. I guess not? So we // try to avoid dealing with other weird icmp's that llvm might use (looking // at you `icmp i0`). switch (bitw) { + case 8: case 16: case 32: @@ -131,8 +153,11 @@ class SplitComparesTransform : public ModulePass { return true; default: return false; + } + } + }; } // namespace @@ -142,6 +167,7 @@ char SplitComparesTransform::ID = 0; /// This function splits FCMP instructions with xGE or xLE predicates into two /// FCMP instructions with predicate xGT or xLT and EQ bool SplitComparesTransform::simplifyFPCompares(Module &M) { + LLVMContext & C = M.getContext(); std::vector fcomps; IntegerType * Int1Ty = IntegerType::getInt1Ty(C); @@ -149,18 +175,23 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* iterate over all functions, bbs and instruction and add * all integer comparisons with >= and <= predicates to the icomps vector */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast(&IN))) { + if (enableFPSplit && (selectcmpInst->getPredicate() == CmpInst::FCMP_OGE || selectcmpInst->getPredicate() == CmpInst::FCMP_UGE || selectcmpInst->getPredicate() == CmpInst::FCMP_OLE || selectcmpInst->getPredicate() == CmpInst::FCMP_ULE)) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -173,16 +204,22 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return false; } /* transform for floating point */ for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -195,6 +232,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::FCMP_UGE: new_pred = CmpInst::FCMP_UGT; break; @@ -209,6 +247,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { break; default: // keep the compiler happy continue; + } /* split before the fcmp instruction */ @@ -252,9 +291,11 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { /* replace the old FcmpInst with our new and shiny PHI inst */ BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); + } return true; + } /// This function splits ICMP instructions with xGE or xLE predicates into two @@ -262,6 +303,7 @@ bool SplitComparesTransform::simplifyFPCompares(Module &M) { bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, Module & M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -278,6 +320,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, CmpInst::Predicate new_pred; switch (pred) { + case CmpInst::ICMP_UGE: new_pred = CmpInst::ICMP_UGT; break; @@ -292,6 +335,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, break; default: // keep the compiler happy return false; + } /* split before the icmp instruction */ @@ -338,6 +382,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, worklist.push_back(icmp_eq); return true; + } /// Simplify a signed comparison operator by splitting it into a unsigned and @@ -345,6 +390,7 @@ bool SplitComparesTransform::simplifyOrEqualsCompare(CmpInst * IcmpInst, /// the worklist passed as a reference. bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpWorklist &worklist) { + LLVMContext &C = M.getContext(); IntegerType *Int1Ty = IntegerType::getInt1Ty(C); @@ -365,10 +411,13 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Predicate new_pred; if (pred == CmpInst::ICMP_SGT) { + new_pred = CmpInst::ICMP_UGT; } else { + new_pred = CmpInst::ICMP_ULT; + } BasicBlock *end_bb = bb->splitBasicBlock(BasicBlock::iterator(IcmpInst)); @@ -391,6 +440,7 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, BasicBlock *sign_bb = BasicBlock::Create(C, "sign", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_SGT) { + /* if we check for > and the op0 positive and op1 negative then the final * result is true. if op0 negative and op1 pos, the cmp must result * in false @@ -399,9 +449,11 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, t_op0, t_op1); } else { + /* just the inverse of the above statement */ icmp_inv_sig_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, t_op0, t_op1); + } sign_bb->getInstList().push_back(icmp_inv_sig_cmp); @@ -439,12 +491,15 @@ bool SplitComparesTransform::simplifySignedCompare(CmpInst *IcmpInst, Module &M, // worklist.push_back(icmp_inv_sig_cmp); return true; + } bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, CmpWorklist &worklist) { + auto pred = cmp_inst->getPredicate(); switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: case CmpInst::ICMP_UGT: @@ -453,6 +508,7 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, default: // unsupported predicate! return false; + } auto op0 = cmp_inst->getOperand(0); @@ -461,14 +517,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // get bitwidth by checking the bitwidth of the first operator IntegerType *intTyOp0 = dyn_cast(op0->getType()); if (!intTyOp0) { + // not an integer type return false; + } unsigned bitw = intTyOp0->getBitWidth(); if (bitw == target_bitwidth) { + // already the target bitwidth so we have to do nothing here. return true; + } LLVMContext &C = M.getContext(); @@ -497,15 +557,17 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, /* now we have to destinguish between == != and > < */ switch (pred) { + case CmpInst::ICMP_EQ: case CmpInst::ICMP_NE: { + /* transformation for == and != icmps */ /* create a compare for the lower half of the original operands */ BasicBlock *cmp_low_bb = BasicBlock::Create(C, "" /*"injected"*/, end_bb->getParent(), end_bb); - Value *op0_low, *op1_low; + Value * op0_low, *op1_low; IRBuilder<> Builder(cmp_low_bb); op0_low = Builder.CreateTrunc(op0, NewIntType); @@ -519,11 +581,16 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, auto term = bb->getTerminator(); BranchInst *br = nullptr; if (pred == CmpInst::ICMP_EQ) { + br = BranchInst::Create(cmp_low_bb, end_bb, icmp_high, bb); + } else { + /* CmpInst::ICMP_NE */ br = BranchInst::Create(end_bb, cmp_low_bb, icmp_high, bb); + } + term->eraseFromParent(); /* create the PHI and connect the edges accordingly */ @@ -531,32 +598,43 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(icmp_low, cmp_low_bb); Value *val = nullptr; if (pred == CmpInst::ICMP_EQ) { + val = ConstantInt::get(Int1Ty, 0); + } else { + /* CmpInst::ICMP_NE */ val = ConstantInt::get(Int1Ty, 1); + } + PN->addIncoming(val, icmp_high->getParent()); break; + } + case CmpInst::ICMP_UGT: case CmpInst::ICMP_ULT: { + /* transformations for < and > */ /* create a basic block which checks for the inverse predicate. * if this is true we can go to the end if not we have to go to the * bb which checks the lower half of the operands */ Instruction *op0_low, *op1_low; - CmpInst *icmp_inv_cmp = nullptr; + CmpInst * icmp_inv_cmp = nullptr; BasicBlock * inv_cmp_bb = BasicBlock::Create(C, "inv_cmp", end_bb->getParent(), end_bb); if (pred == CmpInst::ICMP_UGT) { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_ULT, op0_high, op1_high); } else { + icmp_inv_cmp = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_UGT, op0_high, op1_high); + } inv_cmp_bb->getInstList().push_back(icmp_inv_cmp); @@ -585,9 +663,12 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, PN->addIncoming(ConstantInt::get(Int1Ty, 1), bb); PN->addIncoming(ConstantInt::get(Int1Ty, 0), inv_cmp_bb); break; + } + default: return false; + } BasicBlock::iterator ii(cmp_inst); @@ -597,14 +678,18 @@ bool SplitComparesTransform::splitCompare(CmpInst *cmp_inst, Module &M, // bitwidth we recursivly split the low and high parts again until we have // target bitwidth. if ((bitw / 2) > target_bitwidth) { + worklist.push_back(icmp_high); worklist.push_back(icmp_low); + } return true; + } bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { + CmpWorklist worklist; auto op0 = I->getOperand(0); @@ -625,23 +710,35 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { I->getPredicate() == CmpInst::ICMP_SGE || I->getPredicate() == CmpInst::ICMP_ULE || I->getPredicate() == CmpInst::ICMP_SLE) { + if (!simplifyOrEqualsCompare(I, M, worklist)) { + reportError( "Failed to simplify inequality or equals comparison " "(UGE,SGE,ULE,SLE)", I, M); + } + } else if (I->getPredicate() == CmpInst::ICMP_SGT || + I->getPredicate() == CmpInst::ICMP_SLT) { + if (!simplifySignedCompare(I, M, worklist)) { + reportError("Failed to simplify signed comparison (SGT,SLT)", I, M); + } + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("simpliyfing compare lead to broken function", nullptr, M); + } + #endif // the simplification methods replace the original CmpInst and push the @@ -650,27 +747,38 @@ bool SplitComparesTransform::simplifyAndSplit(CmpInst *I, Module &M) { if (worklist.size() == 0) { worklist.push_back(I); } while (!worklist.empty()) { + CmpInst *cmp = worklist.pop_back_val(); // we split the simplified compares into comparisons with smaller bitwidths // if they are larger than our target_bitwidth. if (bitw > target_bitwidth) { + if (!splitCompare(cmp, M, worklist)) { + reportError("Failed to split comparison", cmp, M); + } #ifdef VERIFY_TOO_MUCH if (verifyFunction(*F, &errs())) { + reportError("splitting compare lead to broken function", nullptr, M); + } + #endif + } + } count++; return true; + } size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { + --in; in |= in >> 1; in |= in >> 2; @@ -678,10 +786,12 @@ size_t SplitComparesTransform::nextPowerOfTwo(size_t in) { // in |= in >> 8; // in |= in >> 16; return in + 1; + } /* splits fcmps into two nested fcmps with sign compare and the rest */ size_t SplitComparesTransform::splitFPCompares(Module &M) { + size_t count = 0; LLVMContext &C = M.getContext(); @@ -693,9 +803,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* define unions with floating point and (sign, exponent, mantissa) triples */ if (dl.isLittleEndian()) { + } else if (dl.isBigEndian()) { + } else { + return count; + } #endif @@ -705,13 +819,17 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { /* get all EQ, NE, GT, and LT fcmps. if the other two * functions were executed only these four predicates should exist */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast(&IN))) { + if (selectcmpInst->getPredicate() == CmpInst::FCMP_OEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_UEQ || selectcmpInst->getPredicate() == CmpInst::FCMP_ONE || @@ -720,6 +838,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { selectcmpInst->getPredicate() == CmpInst::FCMP_OGT || selectcmpInst->getPredicate() == CmpInst::FCMP_ULT || selectcmpInst->getPredicate() == CmpInst::FCMP_OLT) { + auto op0 = selectcmpInst->getOperand(0); auto op1 = selectcmpInst->getOperand(1); @@ -731,10 +850,15 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (TyOp0->isArrayTy() || TyOp0->isVectorTy()) { continue; } fcomps.push_back(selectcmpInst); + } + } + } + } + } if (!fcomps.size()) { return count; } @@ -742,6 +866,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { IntegerType *Int1Ty = IntegerType::getInt1Ty(C); for (auto &FcmpInst : fcomps) { + BasicBlock *bb = FcmpInst->getParent(); auto op0 = FcmpInst->getOperand(0); @@ -866,6 +991,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), t_e1); if (sizeInBits - precision < exTySizeBytes * 8) { + m_e0 = BinaryOperator::Create( Instruction::And, t_e0, ConstantInt::get(t_e0->getType(), mask_exponent)); @@ -878,8 +1004,10 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(signequal_bb->getTerminator()), m_e1); } else { + m_e0 = t_e0; m_e1 = t_e1; + } /* compare the exponents of the operands */ @@ -887,6 +1015,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction *icmp_exponent_result; BasicBlock * signequal2_bb = signequal_bb; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_exponent_result = @@ -956,6 +1085,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } signequal2_bb->getInstList().insert( @@ -963,9 +1093,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { icmp_exponent_result); { + term = signequal2_bb->getTerminator(); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* if the exponents are satifying the compare do a fraction cmp in @@ -988,9 +1120,11 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } term->eraseFromParent(); + } /* isolate the mantissa aka fraction */ @@ -998,6 +1132,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { bool needTrunc = IntFractionTy->getPrimitiveSizeInBits() < op_size; if (precision - 1 < frTySizeBytes * 8) { + Instruction *m_f0, *m_f1; m_f0 = BinaryOperator::Create( Instruction::And, b_op0, @@ -1011,6 +1146,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), m_f1); if (needTrunc) { + t_f0 = new TruncInst(m_f0, IntFractionTy); t_f1 = new TruncInst(m_f1, IntFractionTy); middle_bb->getInstList().insert( @@ -1019,12 +1155,16 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = m_f0; t_f1 = m_f1; + } } else { + if (needTrunc) { + t_f0 = new TruncInst(b_op0, IntFractionTy); t_f1 = new TruncInst(b_op1, IntFractionTy); middle_bb->getInstList().insert( @@ -1033,9 +1173,12 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock::iterator(middle_bb->getTerminator()), t_f1); } else { + t_f0 = b_op0; t_f1 = b_op1; + } + } /* compare the fractions of the operands */ @@ -1043,6 +1186,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { BasicBlock * middle2_bb = middle_bb; PHINode * PN2 = nullptr; switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: icmp_fraction_result = @@ -1065,6 +1209,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { case CmpInst::FCMP_UGT: case CmpInst::FCMP_OLT: case CmpInst::FCMP_ULT: { + Instruction *icmp_fraction_result2; middle2_bb = middle_bb->splitBasicBlock( @@ -1077,6 +1222,7 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { if (FcmpInst->getPredicate() == CmpInst::FCMP_OGT || FcmpInst->getPredicate() == CmpInst::FCMP_UGT) { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); @@ -1085,12 +1231,14 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); } else { + negative_bb->getInstList().push_back( icmp_fraction_result = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_UGT, t_f0, t_f1)); positive_bb->getInstList().push_back( icmp_fraction_result2 = CmpInst::Create( Instruction::ICmp, CmpInst::ICMP_ULT, t_f0, t_f1)); + } BranchInst::Create(middle2_bb, negative_bb); @@ -1110,11 +1258,13 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { default: continue; + } PHINode *PN = PHINode::Create(Int1Ty, 3, ""); switch (FcmpInst->getPredicate()) { + case CmpInst::FCMP_UEQ: case CmpInst::FCMP_OEQ: /* unequal signs cannot be equal values */ @@ -1153,17 +1303,21 @@ size_t SplitComparesTransform::splitFPCompares(Module &M) { break; default: continue; + } BasicBlock::iterator ii(FcmpInst); ReplaceInstWithInst(FcmpInst->getParent()->getInstList(), ii, PN); ++count; + } return count; + } bool SplitComparesTransform::runOnModule(Module &M) { + char *bitw_env = getenv("AFL_LLVM_LAF_SPLIT_COMPARES_BITW"); if (!bitw_env) bitw_env = getenv("LAF_SPLIT_COMPARES_BITW"); if (bitw_env) { target_bitwidth = atoi(bitw_env); } @@ -1172,6 +1326,7 @@ bool SplitComparesTransform::runOnModule(Module &M) { if ((isatty(2) && getenv("AFL_QUIET") == NULL) || getenv("AFL_DEBUG") != NULL) { + errs() << "Split-compare-pass by laf.intel@gmail.com, extended by " "heiko@hexco.de (splitting icmp to " << target_bitwidth << " bit)\n"; @@ -1179,10 +1334,13 @@ bool SplitComparesTransform::runOnModule(Module &M) { if (getenv("AFL_DEBUG") != NULL && !debug) { debug = 1; } } else { + be_quiet = 1; + } if (enableFPSplit) { + count = splitFPCompares(M); /* @@ -1195,55 +1353,76 @@ bool SplitComparesTransform::runOnModule(Module &M) { */ simplifyFPCompares(M); + } std::vector worklist; /* iterate over all functions, bbs and instruction search for all integer * compare instructions. Save them into the worklist for later. */ for (auto &F : M) { + if (!isInInstrumentList(&F)) continue; for (auto &BB : F) { + for (auto &IN : BB) { + if (auto CI = dyn_cast(&IN)) { + auto op0 = CI->getOperand(0); auto op1 = CI->getOperand(1); if (!op0 || !op1) { return false; } auto iTy1 = dyn_cast(op0->getType()); if (iTy1 && isa(op1->getType())) { + unsigned bitw = iTy1->getBitWidth(); if (isSupportedBitWidth(bitw)) { worklist.push_back(CI); } + } + } + } + } + } // now that we have a list of all integer comparisons we can start replacing // them with the splitted alternatives. for (auto CI : worklist) { + simplifyAndSplit(CI, M); + } bool brokenDebug = false; if (verifyModule(M, &errs(), &brokenDebug)) { + reportError( "Module Verifier failed! Consider reporting a bug with the AFL++ " "project.", nullptr, M); + } if (brokenDebug) { + reportError("Module Verifier reported broken Debug Infos - Stripping!", nullptr, M); StripDebugInfo(M); + } + return true; + } static void registerSplitComparesPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) { + PM.add(new SplitComparesTransform()); + } static RegisterStandardPasses RegisterSplitComparesPass( @@ -1262,3 +1441,4 @@ static RegisterPass X("splitcompares", "AFL++ split compares", true /* Only looks at CFG */, true /* Analysis Pass */); + -- cgit 1.4.1 From d2e256e73a2146b125c316e66a96f0215414411b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 14:39:35 +0200 Subject: fix to instrument global c++ namespace functions --- docs/Changelog.md | 3 ++- instrumentation/afl-llvm-common.cc | 5 ++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 0e2ce27d..d3863c74 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -19,9 +19,10 @@ sending a mail to . - afl-cc - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix to instrument global functions in c++ - Fix for llvm 13 - support partial linking - - We do support llvm versions from 3.8 again + - We do support llvm versions from 3.8 to 5.0 again - afl_analyze - fix timeout handling and support forkserver - ensure afl-compiler-rt is built for gcc_module diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index af32e2f9..3239ea91 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -96,9 +96,8 @@ bool isIgnoreFunction(const llvm::Function *F) { static constexpr const char *ignoreSubstringList[] = { - "__asan", "__msan", "__ubsan", "__lsan", - "__san", "__sanitize", "__cxx", "_GLOBAL__", - "DebugCounter", "DwarfDebug", "DebugLoc" + "__asan", "__msan", "__ubsan", "__lsan", "__san", "__sanitize", + "__cxx", "DebugCounter", "DwarfDebug", "DebugLoc" }; -- cgit 1.4.1 From dfff952f5371b184b021fda3a81fbd3fd6b205ac Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 15:07:04 +0200 Subject: update changelog --- docs/Changelog.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index d3863c74..8738ffa3 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -13,20 +13,23 @@ sending a mail to . - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs - removed implied -D determinstic from -M main - - if the target becomes unavailable check out out/default/error.txt for - an indicator why + - if the target becomes unavailable check out out/default/error.txt + for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - - afl-cc - - Update to COMPCOV/laf-intel that speeds up the instrumentation process - a lot - thanks to Michael Rodler/f0rki for the PR! - - Fix to instrument global functions in c++ + - afl-cc: + - Update to COMPCOV/laf-intel that speeds up the instrumentation + process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking - We do support llvm versions from 3.8 to 5.0 again - - afl_analyze - - fix timeout handling and support forkserver + - frida_mode: + - fix for cmplog + - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - afl_analyze: + - fix timeout handling + - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module - - afl-analyze now uses the forkserver for increased performance ### Version ++3.13c (release) -- cgit 1.4.1 From 8c1b0aba5f196e3ae58399b660442e77613c5558 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 11 Jun 2021 15:32:52 +0200 Subject: document frida changes --- README.md | 28 ++++++++++++++-------------- docs/Changelog.md | 2 ++ 2 files changed, 16 insertions(+), 14 deletions(-) (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index bc547b3c..f66eb288 100644 --- a/README.md +++ b/README.md @@ -88,20 +88,20 @@ behaviours and defaults: with laf-intel and redqueen, frida mode, unicorn mode, gcc plugin, full *BSD, Mac OS, Solaris and Android support and much, much, much more. - | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | - | -------------------------|:-------:|:---------:|:----------:|:----------:|:----------------:|:------------:| - | Threadsafe counters | | x(3) | | | | | - | NeverZero | x86[_64]| x(1) | x | x | x | x | - | Persistent Mode | | x | x | x86[_64] | x86[_64]/arm[64] | x | - | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm | - | CmpLog | | x | | x86[_64] | x86[_64]/arm[64] | | - | Selective Instrumentation| | x | x | x | x | | - | Non-Colliding Coverage | | x(4) | | | (x)(5) | | - | Ngram prev_loc Coverage | | x(6) | | | | | - | Context Coverage | | x(6) | | | | | - | Auto Dictionary | | x(7) | | | | | - | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | - | Shared Memory Testcases | | x | x | x | x | x | + | Feature/Instrumentation | afl-gcc | llvm | gcc_plugin | frida_mode | qemu_mode |unicorn_mode | + | -------------------------|:-------:|:---------:|:----------:|:----------------:|:----------------:|:----------------:| + | Threadsafe counters | | x(3) | | | | | + | NeverZero | x86[_64]| x(1) | x | x | x | x | + | Persistent Mode | | x | x | x86[_64]/arm[64] | x86[_64]/arm[64] | x | + | LAF-Intel / CompCov | | x | | | x86[_64]/arm[64] | x86[_64]/arm[64] | + | CmpLog | | x | | x86[_64]/arm[64] | x86[_64]/arm[64] | | + | Selective Instrumentation| | x | x | x | x | | + | Non-Colliding Coverage | | x(4) | | | (x)(5) | | + | Ngram prev_loc Coverage | | x(6) | | | | | + | Context Coverage | | x(6) | | | | | + | Auto Dictionary | | x(7) | | | | | + | Snapshot LKM Support | | (x)(8) | (x)(8) | | (x)(5) | | + | Shared Memory Testcases | | x | x | x | x | x | 1. default for LLVM >= 9.0, env var for older version due an efficiency bug in previous llvm versions 2. GCC creates non-performant code, hence it is disabled in gcc_plugin diff --git a/docs/Changelog.md b/docs/Changelog.md index eebcaed4..9f70535a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -26,6 +26,8 @@ sending a mail to . - frida_mode: - fix for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - feature parity of aarch64 with intel now (persistent, cmplog, + in-memory testcases, asan) - afl_analyze: - fix timeout handling - add forkserver support for better performance -- cgit 1.4.1 From a6c0b5f7667475336a26197d99ea24f18ffcdbd7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 11:46:26 +0200 Subject: afl-cmin/afl-cmin.bash/afl-showmap -i descend into subdirectories --- docs/Changelog.md | 2 + src/afl-showmap.c | 159 ++++++++++++++++++++++++++++++++---------------------- 2 files changed, 96 insertions(+), 65 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9f70535a..530dd941 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,6 +31,8 @@ sending a mail to . - afl_analyze: - fix timeout handling - add forkserver support for better performance + - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into + subdirectories (like afl-fuzz does) - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 96b72dd9..03050d91 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -67,6 +67,8 @@ static char *stdin_file; /* stdin file */ static u8 *in_dir = NULL, /* input folder */ *out_file = NULL, *at_file = NULL; /* Substitution string for @@ */ +static u8 outfile[PATH_MAX]; + static u8 *in_data, /* Input data */ *coverage_map; /* Coverage map */ @@ -88,7 +90,8 @@ static bool quiet_mode, /* Hide non-essential messages? */ have_coverage, /* have coverage? */ no_classify, /* do not classify counts */ debug, /* debug mode */ - print_filenames; /* print the current filename */ + print_filenames, /* print the current filename */ + wait_for_gdb; static volatile u8 stop_soon, /* Ctrl-C pressed? */ child_crashed; /* Child crashed? */ @@ -692,6 +695,93 @@ static void setup_signal_handlers(void) { } +u32 execute_testcases(u8 *dir) { + + struct dirent **nl; + s32 nl_cnt, subdirs = 1; + u32 i, done = 0; + u8 val_buf[2][STRINGIFY_VAL_SIZE_MAX]; + + if (!be_quiet) { ACTF("Scanning '%s'...", dir); } + + /* We use scandir() + alphasort() rather than readdir() because otherwise, + the ordering of test cases would vary somewhat randomly and would be + difficult to control. */ + + nl_cnt = scandir(dir, &nl, NULL, alphasort); + + if (nl_cnt < 0) { return 0; } + + for (i = 0; i < (u32)nl_cnt; ++i) { + + struct stat st; + + u8 *fn2 = alloc_printf("%s/%s", dir, nl[i]->d_name); + + if (lstat(fn2, &st) || access(fn2, R_OK)) { + + PFATAL("Unable to access '%s'", fn2); + + } + + /* obviously we want to skip "descending" into . and .. directories, + however it is a good idea to skip also directories that start with + a dot */ + if (subdirs && S_ISDIR(st.st_mode) && nl[i]->d_name[0] != '.') { + + free(nl[i]); /* not tracked */ + done += execute_testcases(fn2); + ck_free(fn2); + continue; + + } + + free(nl[i]); + + if (!S_ISREG(st.st_mode) || !st.st_size) { + + ck_free(fn2); + continue; + + } + + if (st.st_size > MAX_FILE && !be_quiet) { + + WARNF("Test case '%s' is too big (%s, limit is %s), partial reading", fn2, + stringify_mem_size(val_buf[0], sizeof(val_buf[0]), st.st_size), + stringify_mem_size(val_buf[1], sizeof(val_buf[1]), MAX_FILE)); + + } + + // DO + if (read_file(fn2)) { + + if (wait_for_gdb) { + + fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); + fprintf(stderr, "exec: kill -CONT %d\n", getpid()); + kill(0, SIGSTOP); + + } + + showmap_run_target_forkserver(fsrv, in_data, in_len); + ck_free(in_data); + ++done; + + if (collect_coverage) + analyze_results(fsrv); + else + tcnt = write_results_to_file(fsrv, outfile); + + } + + } + + free(nl); /* not tracked */ + return done; + +} + /* Show banner. */ static void show_banner(void) { @@ -1136,15 +1226,7 @@ int main(int argc, char **argv_orig, char **envp) { if (in_dir) { - DIR * dir_in, *dir_out = NULL; - struct dirent **file_list; - - // int done = 0; - u8 infile[PATH_MAX], outfile[PATH_MAX]; - u8 wait_for_gdb = 0; -#if !defined(DT_REG) - struct stat statbuf; -#endif + DIR *dir_in, *dir_out = NULL; if (getenv("AFL_DEBUG_GDB")) wait_for_gdb = true; @@ -1245,65 +1327,12 @@ int main(int argc, char **argv_orig, char **envp) { if (fsrv->support_shmem_fuzz && !fsrv->use_shmem_fuzz) shm_fuzz = deinit_shmem(fsrv, shm_fuzz); - int file_count = scandir(in_dir, &file_list, NULL, alphasort); - if (file_count < 0) { + if (execute_testcases(in_dir) == 0) { - PFATAL("Failed to read from input dir at %s\n", in_dir); + FATAL("could not read input testcases from %s", in_dir); } - for (int i = 0; i < file_count; i++) { - - struct dirent *dir_ent = file_list[i]; - - if (dir_ent->d_name[0] == '.') { - - continue; // skip anything that starts with '.' - - } - -#if defined(DT_REG) /* Posix and Solaris do not know d_type and DT_REG */ - if (dir_ent->d_type != DT_REG) { - - continue; // only regular files - - } - -#endif - - snprintf(infile, sizeof(infile), "%s/%s", in_dir, dir_ent->d_name); - -#if !defined(DT_REG) /* use stat() */ - if (-1 == stat(infile, &statbuf) || !S_ISREG(statbuf.st_mode)) continue; -#endif - - if (!collect_coverage) - snprintf(outfile, sizeof(outfile), "%s/%s", out_file, dir_ent->d_name); - - if (read_file(infile)) { - - if (wait_for_gdb) { - - fprintf(stderr, "exec: gdb -p %d\n", fsrv->child_pid); - fprintf(stderr, "exec: kill -CONT %d\n", getpid()); - kill(0, SIGSTOP); - - } - - showmap_run_target_forkserver(fsrv, in_data, in_len); - ck_free(in_data); - if (collect_coverage) - analyze_results(fsrv); - else - tcnt = write_results_to_file(fsrv, outfile); - - } - - } - - free(file_list); - file_list = NULL; - if (!quiet_mode) { OKF("Processed %llu input files.", fsrv->total_execs); } if (dir_out) { closedir(dir_out); } -- cgit 1.4.1 From c46f8c1f70918056e95c801b1a81f11c79304b05 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 16 Jun 2021 13:03:42 +0200 Subject: make afl-cmin actually work with subdirectories --- afl-cmin | 42 ++++++++++++++++++-------------- docs/Changelog.md | 4 ++-- instrumentation/afl-compiler-rt.o.c | 2 +- src/afl-showmap.c | 48 +++++++++++++++++++++---------------- 4 files changed, 54 insertions(+), 42 deletions(-) (limited to 'docs/Changelog.md') diff --git a/afl-cmin b/afl-cmin index 9fa63ec6..e71873d3 100755 --- a/afl-cmin +++ b/afl-cmin @@ -296,13 +296,13 @@ BEGIN { exit 1 } - if (0 == system( "test -d "in_dir"/default" )) { - in_dir = in_dir "/default" - } - - if (0 == system( "test -d "in_dir"/queue" )) { - in_dir = in_dir "/queue" - } + #if (0 == system( "test -d "in_dir"/default" )) { + # in_dir = in_dir "/default" + #} + # + #if (0 == system( "test -d "in_dir"/queue" )) { + # in_dir = in_dir "/queue" + #} system("rm -rf "trace_dir" 2>/dev/null"); system("rm "out_dir"/id[:_]* 2>/dev/null") @@ -355,30 +355,35 @@ BEGIN { } else { stat_format = "-f '%z %N'" # *BSD, MacOS } - cmdline = "(cd "in_dir" && find . \\( ! -name . -a -type d -prune \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" + cmdline = "(cd "in_dir" && find . \\( ! -name \".*\" -a -type d \\) -o -type f -exec stat "stat_format" \\{\\} + | sort -k1n -k2r)" #cmdline = "ls "in_dir" | (cd "in_dir" && xargs stat "stat_format" 2>/dev/null) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && stat "stat_format" *) | sort -k1n -k2r" #cmdline = "(cd "in_dir" && ls | xargs stat "stat_format" ) | sort -k1n -k2r" while (cmdline | getline) { sub(/^[0-9]+ (\.\/)?/,"",$0) - infilesSmallToBig[i++] = $0 + infilesSmallToBigFull[i] = $0 + sub(/.*\//, "", $0) + infilesSmallToBig[i] = $0 + infilesSmallToBigMap[infilesSmallToBig[i]] = infilesSmallToBigFull[i] + infilesSmallToBigFullMap[infilesSmallToBigFull[i]] = infilesSmallToBig[i] + i++ } in_count = i - first_file = infilesSmallToBig[0] + first_file = infilesSmallToBigFull[0] - # Make sure that we're not dealing with a directory. - - if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { - print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" - exit 1 - } + #if (0 == system("test -d ""\""in_dir"/"first_file"\"")) { + # print "[-] Error: The input directory is empty or contains subdirectories - please fix." > "/dev/stderr" + # exit 1 + #} - if (0 == system("ln \""in_dir"/"first_file"\" "trace_dir"/.link_test")) { + system(">\""in_dir"/.afl-cmin.test\"") + if (0 == system("ln \""in_dir"/.afl-cmin.test\" "trace_dir"/.link_test")) { cp_tool = "ln" } else { cp_tool = "cp" } + system("rm -f \""in_dir"/.afl-cmin.test\"") if (!ENVIRON["AFL_SKIP_BIN_CHECK"]) { # Make sure that we can actually get anything out of afl-showmap before we @@ -511,7 +516,8 @@ BEGIN { # copy file unless already done if (! (fn in file_already_copied)) { - system(cp_tool" \""in_dir"/"fn"\" \""out_dir"/"fn"\"") + realfile = infilesSmallToBigMap[fn] + system(cp_tool" \""in_dir"/"realfile"\" \""out_dir"/"fn"\"") file_already_copied[fn] = "" ++out_count #printf "tuple nr %d (%d cnt=%d) -> %s\n",tcnt,key,key_count[key],fn > trace_dir"/.log" diff --git a/docs/Changelog.md b/docs/Changelog.md index 530dd941..9fd2a1a9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -31,8 +31,8 @@ sending a mail to . - afl_analyze: - fix timeout handling - add forkserver support for better performance - - afl-cmin, afl-cmin.bash and afl-showmap -i do now descend into - subdirectories (like afl-fuzz does) + - afl-cmin and afl-showmap -i do now descend into subdirectories + (like afl-fuzz does) - note that afl-cmin.bash does not! - ensure afl-compiler-rt is built for gcc_module ### Version ++3.13c (release) diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 50117012..404b761f 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -1019,7 +1019,7 @@ static void __afl_start_forkserver(void) { if (read(FORKSRV_FD, &was_killed, 4) != 4) { - write_error("read from afl-fuzz"); + //write_error("read from afl-fuzz"); _exit(1); } diff --git a/src/afl-showmap.c b/src/afl-showmap.c index 03050d91..646396ad 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -233,7 +233,11 @@ static u32 write_results_to_file(afl_forkserver_t *fsrv, u8 *outfile) { u8 cco = !!getenv("AFL_CMIN_CRASHES_ONLY"), caa = !!getenv("AFL_CMIN_ALLOW_ANY"); - if (!outfile) { FATAL("Output filename not set (Bug in AFL++?)"); } + if (!outfile || !*outfile) { + + FATAL("Output filename not set (Bug in AFL++?)"); + + } if (cmin_mode && (fsrv->last_run_timed_out || (!caa && child_crashed != cco))) { @@ -753,7 +757,9 @@ u32 execute_testcases(u8 *dir) { } - // DO + if (!collect_coverage) + snprintf(outfile, sizeof(outfile), "%s/%s", out_file, nl[i]->d_name); + if (read_file(fn2)) { if (wait_for_gdb) { @@ -800,31 +806,31 @@ static void usage(u8 *argv0) { "\n%s [ options ] -- /path/to/target_app [ ... ]\n\n" "Required parameters:\n" - " -o file - file to write the trace data to\n\n" + " -o file - file to write the trace data to\n\n" "Execution control settings:\n" - " -t msec - timeout for each run (none)\n" - " -m megs - memory limit for child process (%u MB)\n" - " -O - use binary-only instrumentation (FRIDA mode)\n" - " -Q - use binary-only instrumentation (QEMU mode)\n" - " -U - use Unicorn-based instrumentation (Unicorn mode)\n" - " -W - use qemu-based instrumentation with Wine (Wine mode)\n" - " (Not necessary, here for consistency with other afl-* " + " -t msec - timeout for each run (none)\n" + " -m megs - memory limit for child process (%u MB)\n" + " -O - use binary-only instrumentation (FRIDA mode)\n" + " -Q - use binary-only instrumentation (QEMU mode)\n" + " -U - use Unicorn-based instrumentation (Unicorn mode)\n" + " -W - use qemu-based instrumentation with Wine (Wine mode)\n" + " (Not necessary, here for consistency with other afl-* " "tools)\n\n" "Other settings:\n" - " -i dir - process all files in this directory, must be combined " + " -i dir - process all files below this directory, must be combined " "with -o.\n" - " With -C, -o is a file, without -C it must be a " + " With -C, -o is a file, without -C it must be a " "directory\n" - " and each bitmap will be written there individually.\n" - " -C - collect coverage, writes all edges to -o and gives a " + " and each bitmap will be written there individually.\n" + " -C - collect coverage, writes all edges to -o and gives a " "summary\n" - " Must be combined with -i.\n" - " -q - sink program's output and don't show messages\n" - " -e - show edge coverage only, ignore hit counts\n" - " -r - show real tuple values instead of AFL filter values\n" - " -s - do not classify the map\n" - " -c - allow core dumps\n\n" + " Must be combined with -i.\n" + " -q - sink program's output and don't show messages\n" + " -e - show edge coverage only, ignore hit counts\n" + " -r - show real tuple values instead of AFL filter values\n" + " -s - do not classify the map\n" + " -c - allow core dumps\n\n" "This tool displays raw tuple data captured by AFL instrumentation.\n" "For additional help, consult %s/README.md.\n\n" @@ -1259,7 +1265,7 @@ int main(int argc, char **argv_orig, char **envp) { } else { - if ((coverage_map = (u8 *)malloc(map_size)) == NULL) + if ((coverage_map = (u8 *)malloc(map_size + 64)) == NULL) FATAL("coult not grab memory"); edges_only = false; raw_instr_output = true; -- cgit 1.4.1 From cbac22d82b90d631bafc4572aa79faa0c568beeb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 22 Jun 2021 17:24:06 +0200 Subject: reverse read the queue n resumes --- docs/Changelog.md | 1 + src/afl-fuzz-init.c | 7 +++++-- src/afl-fuzz-run.c | 3 ++- src/afl-fuzz.c | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 9fd2a1a9..afa5491b 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -16,6 +16,7 @@ sending a mail to . - if the target becomes unavailable check out out/default/error.txt for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL + - reverse read the queue on resumes (more effective) - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! diff --git a/src/afl-fuzz-init.c b/src/afl-fuzz-init.c index 872e3a32..cc5974d8 100644 --- a/src/afl-fuzz-init.c +++ b/src/afl-fuzz-init.c @@ -710,7 +710,10 @@ void read_testcases(afl_state_t *afl, u8 *directory) { } - for (i = 0; i < (u32)nl_cnt; ++i) { + i = nl_cnt; + do { + + --i; struct stat st; @@ -801,7 +804,7 @@ void read_testcases(afl_state_t *afl, u8 *directory) { */ - } + } while (i > 0); free(nl); /* not tracked */ diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 3de67955..49856a9f 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -424,7 +424,8 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } var_detected = 1; - afl->stage_max = afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; + afl->stage_max = + afl->afl_env.afl_cal_fast ? CAL_CYCLES : CAL_CYCLES_LONG; } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index c148086c..5f25f728 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -1911,7 +1911,12 @@ int main(int argc, char **argv_orig, char **envp) { if (unlikely(afl->old_seed_selection)) seek_to = find_start_position(afl); afl->start_time = get_cur_time(); - if (afl->in_place_resume || afl->afl_env.afl_autoresume) load_stats_file(afl); + if (afl->in_place_resume || afl->afl_env.afl_autoresume) { + + load_stats_file(afl); + + } + write_stats_file(afl, 0, 0, 0, 0); maybe_update_plot_file(afl, 0, 0, 0); save_auto(afl); -- cgit 1.4.1 From ff4d45eed25d9ab80441f813916034bb38cff01e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 22 Jun 2021 22:05:28 +0200 Subject: cmplog fix for qemu and frida --- docs/Changelog.md | 4 +++- instrumentation/afl-compiler-rt.o.c | 17 +++++++++-------- src/afl-forkserver.c | 3 +-- 3 files changed, 13 insertions(+), 11 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index afa5491b..4dd68cd2 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -25,10 +25,12 @@ sending a mail to . - support partial linking - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - - fix for cmplog + - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) + - qemu_mode: + - performance fix when cmplog was used - afl_analyze: - fix timeout handling - add forkserver support for better performance diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 92deff6a..d4529e2c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -617,6 +617,7 @@ static void __afl_unmap_shm(void) { #endif __afl_cmp_map = NULL; + __afl_cmp_map_backup = NULL; } @@ -1684,7 +1685,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (k >> 4) ^ (k << 8); @@ -1788,7 +1789,7 @@ void __sanitizer_cov_trace_const_cmp16(uint128_t arg1, uint128_t arg2) { void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; for (uint64_t i = 0; i < cases[0]; i++) { @@ -1885,7 +1886,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { fprintf(stderr, "\n"); */ - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); int l1, l2; if ((l1 = area_is_valid(ptr1, 32)) <= 0 || @@ -1969,7 +1970,7 @@ static u8 *get_llvm_stdstring(u8 *string) { void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -1979,7 +1980,7 @@ void __cmplog_rtn_gcc_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -1990,7 +1991,7 @@ void __cmplog_rtn_gcc_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring, 32) <= 0 || area_is_valid(cstring, 32) <= 0) return; @@ -2000,7 +2001,7 @@ void __cmplog_rtn_llvm_stdstring_cstring(u8 *stdstring, u8 *cstring) { void __cmplog_rtn_llvm_stdstring_stdstring(u8 *stdstring1, u8 *stdstring2) { - if (unlikely(!__afl_cmp_map)) return; + if (likely(!__afl_cmp_map)) return; if (area_is_valid(stdstring1, 32) <= 0 || area_is_valid(stdstring2, 32) <= 0) return; @@ -2034,7 +2035,7 @@ void __afl_coverage_on() { if (likely(__afl_selective_coverage && __afl_selective_coverage_temp)) { __afl_area_ptr = __afl_area_ptr_backup; - __afl_cmp_map = __afl_cmp_map_backup; + if (__afl_cmp_map_backup) { __afl_cmp_map = __afl_cmp_map_backup; } } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 8fb8a75a..5e8fb9b5 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -418,8 +418,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, struct rlimit r; - if (!fsrv->cmplog_binary && fsrv->qemu_mode == false && - fsrv->frida_mode == false) { + if (!fsrv->cmplog_binary) { unsetenv(CMPLOG_SHM_ENV_VAR); // we do not want that in non-cmplog fsrv -- cgit 1.4.1 From a6cf9bb336cc3e166469d6eed206a2b6fa9c994a Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 1 Jul 2021 08:20:32 +0200 Subject: update honggfuzz custom mutator --- custom_mutators/honggfuzz/honggfuzz.h | 5 +++-- docs/Changelog.md | 2 -- unicorn_mode/unicornafl | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'docs/Changelog.md') diff --git a/custom_mutators/honggfuzz/honggfuzz.h b/custom_mutators/honggfuzz/honggfuzz.h index c80cdd87..51c7b567 100644 --- a/custom_mutators/honggfuzz/honggfuzz.h +++ b/custom_mutators/honggfuzz/honggfuzz.h @@ -246,9 +246,9 @@ typedef struct { } timing; struct { struct { - uint8_t val[256]; + uint8_t val[512]; size_t len; - } dictionary[1024]; + } dictionary[8192]; size_t dictionaryCnt; const char* dictionaryFile; size_t mutationsMax; @@ -263,6 +263,7 @@ typedef struct { struct { bool useVerifier; bool exitUponCrash; + uint8_t exitCodeUponCrash; const char* reportFile; size_t dynFileIterExpire; bool only_printable; diff --git a/docs/Changelog.md b/docs/Changelog.md index 475240c2..461acb2c 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -29,8 +29,6 @@ sending a mail to . - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) - - qemu_mode: - - performance fix when cmplog was used - afl-cmin and afl-showmap -i do now descend into subdirectories (like afl-fuzz does) - note that afl-cmin.bash does not! - afl_analyze: diff --git a/unicorn_mode/unicornafl b/unicorn_mode/unicornafl index 0d82727f..019b8715 160000 --- a/unicorn_mode/unicornafl +++ b/unicorn_mode/unicornafl @@ -1 +1 @@ -Subproject commit 0d82727f2b477de82fa355edef9bc158bd25d374 +Subproject commit 019b871539fe9ed3f41d882385a8b02c243d49ad -- cgit 1.4.1 From f1bcd378a2e55ee1559dde0d46e2bc32882c5b39 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 7 Jul 2021 12:19:05 +0200 Subject: fix failures for some sized string instrumentations --- docs/Changelog.md | 1 + instrumentation/SanitizerCoverageLTO.so.cc | 12 ++++++++++++ instrumentation/afl-llvm-dict2file.so.cc | 13 ++++++++++++- instrumentation/afl-llvm-lto-instrumentation.so.cc | 7 +++++++ instrumentation/compare-transform-pass.so.cc | 19 +++++-------------- 5 files changed, 37 insertions(+), 15 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 461acb2c..c3e4b34e 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -20,6 +20,7 @@ sending a mail to . - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! + - Fix for failures for some sized string instrumentations - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 372af003..28eb0b9f 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -759,6 +759,12 @@ bool ModuleSanitizerCoverage::instrumentModule( uint64_t literalLength = Str2.size(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -862,6 +868,12 @@ bool ModuleSanitizerCoverage::instrumentModule( uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > thestring.length() + 1) { + + optLen = thestring.length() + 1; + + } + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index e2b44b21..5350f62b 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -428,6 +428,12 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = Str2.length(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -534,7 +540,12 @@ bool AFLdict2filePass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); - if (optLen > thestring.length()) { optLen = thestring.length(); } + if (optLen > thestring.length() + 1) { + + optLen = thestring.length() + 1; + + } + if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index bb9b9279..263d947d 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -546,6 +546,12 @@ bool AFLLTOPass::runOnModule(Module &M) { uint64_t literalLength = Str2.size(); uint64_t optLength = ilen->getZExtValue(); + if (optLength > literalLength + 1) { + + optLength = Str2.length() + 1; + + } + if (literalLength + 1 == optLength) { Str2.append("\0", 1); // add null byte @@ -649,6 +655,7 @@ bool AFLLTOPass::runOnModule(Module &M) { uint64_t literalLength = optLen; optLen = ilen->getZExtValue(); + if (optLen > literalLength + 1) { optLen = literalLength + 1; } if (optLen < 2) { continue; } if (literalLength + 1 == optLen) { // add null byte thestring.append("\0", 1); diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 3ecba4e6..f5dd4a53 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -313,27 +313,18 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, ConstantInt *ilen = dyn_cast(op2); if (ilen) { - uint64_t len = ilen->getZExtValue(); // if len is zero this is a pointless call but allow real // implementation to worry about that - if (len < 2) continue; + if (ilen->getZExtValue() < 2) { continue; } - if (isMemcmp) { - - // if size of compare is larger than constant string this is - // likely a bug but allow real implementation to worry about - // that - uint64_t literalLength = HasStr1 ? Str1.size() : Str2.size(); - if (literalLength + 1 < ilen->getZExtValue()) continue; - - } - - } else if (isMemcmp) + } else if (isMemcmp) { // this *may* supply a len greater than the constant string at // runtime so similarly we don't want to have to handle that continue; + } + } calls.push_back(callInst); @@ -421,7 +412,7 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } if (TmpConstStr.length() < 2 || - (TmpConstStr.length() == 2 && !TmpConstStr[1])) { + (TmpConstStr.length() == 2 && TmpConstStr[1] == 0)) { continue; -- cgit 1.4.1 From b6a9e54c60e98e5c27404253295ce06648bcbd18 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Tue, 13 Jul 2021 11:03:30 +0200 Subject: Added more AFL_NO_FORKSRV docu, changelog --- afl-cmin | 1 + afl-cmin.bash | 1 + docs/Changelog.md | 2 ++ 3 files changed, 4 insertions(+) (limited to 'docs/Changelog.md') diff --git a/afl-cmin b/afl-cmin index e71873d3..e6f8c175 100755 --- a/afl-cmin +++ b/afl-cmin @@ -122,6 +122,7 @@ function usage() { "AFL_FORKSRV_INIT_TMOUT: time the fuzzer waits for the forkserver to come up\n" \ "AFL_KEEP_TRACES: leave the temporary /.traces directory\n" \ "AFL_KILL_SIGNAL: Signal delivered to child processes on timeout (default: SIGKILL)\n" \ +"AFL_NO_FORKSRV: run target via execve instead of using the forkserver\n" \ "AFL_PATH: path for the afl-showmap binary if not found anywhere in PATH\n" \ "AFL_PRINT_FILENAMES: If set, the filename currently processed will be " \ "printed to stdout\n" \ diff --git a/afl-cmin.bash b/afl-cmin.bash index f4bd269d..c77dfbc1 100755 --- a/afl-cmin.bash +++ b/afl-cmin.bash @@ -135,6 +135,7 @@ For additional tips, please consult README.md. Environment variables used: AFL_KEEP_TRACES: leave the temporary \.traces directory +AFL_NO_FORKSRV: run target via execve instead of using the forkserver AFL_PATH: last resort location to find the afl-showmap binary AFL_SKIP_BIN_CHECK: skip check for target binary _EOF_ diff --git a/docs/Changelog.md b/docs/Changelog.md index c3e4b34e..aebd3fa9 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -36,6 +36,8 @@ sending a mail to . - fix timeout handling - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module + - added `AFL_NO_FORKSRV` env variable support to + afl-cmin, afl-tmin, and afl-showmap, by @jhertz ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 -- cgit 1.4.1 From 3a3ef7b6b4efcd8ed12bef80cca51f82e65a985f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 12:16:52 +0200 Subject: update documentation --- README.md | 55 ++++++++++++- docs/Changelog.md | 1 + docs/QuickStartGuide.md | 9 +-- docs/README.MOpt.md | 54 ------------- docs/historical_notes.md | 143 -------------------------------- docs/notes_for_asan.md | 157 ------------------------------------ docs/perf_tips.md | 47 ++++------- docs/power_schedules.md | 32 -------- docs/technical_details.md | 4 + instrumentation/afl-compiler-rt.o.c | 5 +- 10 files changed, 79 insertions(+), 428 deletions(-) delete mode 100644 docs/README.MOpt.md delete mode 100644 docs/historical_notes.md delete mode 100644 docs/notes_for_asan.md delete mode 100644 docs/power_schedules.md (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index bc5b333c..50f514ab 100644 --- a/README.md +++ b/README.md @@ -387,7 +387,56 @@ afl++ performs "never zero" counting in its bitmap. You can read more about this here: * [instrumentation/README.neverzero.md](instrumentation/README.neverzero.md) -#### c) Modify the target +#### c) Sanitizers + +It is possible to use sanitizers when instrumenting targets for fuzzing, +which allows you to find bugs that would not necessarily result in a crash. + +Note that sanitizers have a huge impact on CPU (= less executions per second) +and RAM usage. Also you should only run one afl-fuz instance per sanitizer type. +This is enough because a user-after-free bug will be picked up, e.g. by +ASAN (address sanitizer) anyway when syncing to other fuzzing instances, +so not all fuzzing instances need to be instrumented with ASAN. + +The wolloing sanitizers have built-in support in afl++: + * ASAN = Address SANitizer, finds memory corruption vulnerabilities like + use-after-free, NULL pointer dereference, buffer overruns, etc. + Enabled with `export AFL_USE_ASAN=1` before compiling. + * MSAN = Memory SANitizer, finds read access to uninitialized memory, eg. + a local variable that is defined and read before it is even set. + Enabled with `export AFL_USE_MSAN=1` before compiling. + * UBSAN = Undefined Behaviour SANitizer, finds instances where - by the + C and C++ standards - undefined behaviour happens, e.g. adding two + signed integers together where the result is larger than a signed integer + can hold. + Enabled with `export AFL_USE_UBSAN=1` before compiling. + * CFISAN = Control Flow Integrity SANitizer, finds instances where the + control flow is found to be illegal. Originally this was rather to + prevent return oriented programming exploit chains from functioning, + in fuzzing this is mostly reduced to detecting type confusion + vulnerabilities - which is however one of the most important and dangerous + C++ memory corruption classes! + Enabled with `export AFL_USE_CFISAN=1` before compiling. + * LSAN = Leak SANitizer, finds memory leaks in a program. This is not really + a security issue, but for developers this can be very valuable. + Note that unlike the other sanitizers above this needs + `__AFL_LEAK_CHECK();` added to all areas of the target source code where you + find a leak check necessary! + Enabled with `export AFL_USE_LSAN=1` before compiling. + +It is possible to further modify the behaviour of the sanitizers at run-time +by setting `ASAN_OPTIONS=...`, `LSAN_OPTIONS` etc. - the availabel parameter +can be looked up in the sanitizer documentation of llvm/clang. +afl-fuzz however requires some specific parameters important for fuzzing to be +set if you want to set your own, and will bail and report what it is missing. + +Note that some sanitizers cannot be used together, e.g. ASAN and MSAN, and +others often cannot work together because of target weirdness, e.g. ASAN and +CFISAN. You might need to experiment which sanitizers you can combine in a +target (which means more instances can be run without a sanitized target, +which is more effective). + +#### d) Modify the target If the target has features that make fuzzing more difficult, e.g. checksums, HMAC, etc. then modify the source code so that this is @@ -405,7 +454,7 @@ these checks within this specific defines: All afl++ compilers will set this preprocessor definition automatically. -#### d) Instrument the target +#### e) Instrument the target In this step the target source code is compiled so that it can be fuzzed. @@ -462,7 +511,7 @@ non-standard way to set this, otherwise set up the build normally and edit the generated build environment afterwards manually to point it to the right compiler (and/or ranlib and ar). -#### d) Better instrumentation +#### f) Better instrumentation If you just fuzz a target program as-is you are wasting a great opportunity for much more fuzzing speed. diff --git a/docs/Changelog.md b/docs/Changelog.md index aebd3fa9..705daa40 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -38,6 +38,7 @@ sending a mail to . - ensure afl-compiler-rt is built for gcc_module - added `AFL_NO_FORKSRV` env variable support to afl-cmin, afl-tmin, and afl-showmap, by @jhertz + - removed outdated documents, improved existing documentation ### Version ++3.13c (release) - Note: plot_data switched to relative time from unix time in 3.10 diff --git a/docs/QuickStartGuide.md b/docs/QuickStartGuide.md index d1966170..2d056ecf 100644 --- a/docs/QuickStartGuide.md +++ b/docs/QuickStartGuide.md @@ -18,14 +18,12 @@ how to hit the ground running: custom SIGSEGV or SIGABRT handlers and background processes. For tips on detecting non-crashing flaws, see section 11 in [README.md](README.md) . -3) Compile the program / library to be fuzzed using afl-gcc. A common way to +3) Compile the program / library to be fuzzed using afl-cc. A common way to do this would be: - CC=/path/to/afl-gcc CXX=/path/to/afl-g++ ./configure --disable-shared + CC=/path/to/afl-cc CXX=/path/to/afl-c++ ./configure --disable-shared make clean all - If program build fails, ping . - 4) Get a small but valid input file that makes sense to the program. When fuzzing verbose syntax (SQL, HTTP, etc), create a dictionary as described in dictionaries/README.md, too. @@ -41,9 +39,6 @@ how to hit the ground running: 6) Investigate anything shown in red in the fuzzer UI by promptly consulting [status_screen.md](status_screen.md). -7) compile and use llvm_mode (afl-clang-fast/afl-clang-fast++) as it is way - faster and has a few cool features - 8) There is a basic docker build with 'docker build -t aflplusplus .' That's it. Sit back, relax, and - time permitting - try to skim through the diff --git a/docs/README.MOpt.md b/docs/README.MOpt.md deleted file mode 100644 index 3de6d670..00000000 --- a/docs/README.MOpt.md +++ /dev/null @@ -1,54 +0,0 @@ -# MOpt(imized) AFL by - -### 1. Description -MOpt-AFL is a AFL-based fuzzer that utilizes a customized Particle Swarm -Optimization (PSO) algorithm to find the optimal selection probability -distribution of operators with respect to fuzzing effectiveness. -More details can be found in the technical report. - -### 2. Cite Information -Chenyang Lyu, Shouling Ji, Chao Zhang, Yuwei Li, Wei-Han Lee, Yu Song and -Raheem Beyah, MOPT: Optimized Mutation Scheduling for Fuzzers, -USENIX Security 2019. - -### 3. Seed Sets -We open source all the seed sets used in the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers". - -### 4. Experiment Results -The experiment results can be found in -https://drive.google.com/drive/folders/184GOzkZGls1H2NuLuUfSp9gfqp1E2-lL?usp=sharing. -We only open source the crash files since the space is limited. - -### 5. Technical Report -MOpt_TechReport.pdf is the technical report of the paper -"MOPT: Optimized Mutation Scheduling for Fuzzers", which contains more deatails. - -### 6. Parameter Introduction -Most important, you must add the parameter `-L` (e.g., `-L 0`) to launch the -MOpt scheme. - -Option '-L' controls the time to move on to the pacemaker fuzzing mode. -'-L t': when MOpt-AFL finishes the mutation of one input, if it has not -discovered any new unique crash or path for more than t minutes, MOpt-AFL will -enter the pacemaker fuzzing mode. - -Setting 0 will enter the pacemaker fuzzing mode at first, which is -recommended in a short time-scale evaluation. - -Setting -1 will enable both pacemaker mode and normal aflmutation fuzzing in -parallel. - -Other important parameters can be found in afl-fuzz.c, for instance, - -'swarm_num': the number of the PSO swarms used in the fuzzing process. -'period_pilot': how many times MOpt-AFL will execute the target program - in the pilot fuzzing module, then it will enter the core fuzzing module. -'period_core': how many times MOpt-AFL will execute the target program in the - core fuzzing module, then it will enter the PSO updating module. -'limit_time_bound': control how many interesting test cases need to be found - before MOpt-AFL quits the pacemaker fuzzing mode and reuses the deterministic stage. - 0 < 'limit_time_bound' < 1, MOpt-AFL-tmp. - 'limit_time_bound' >= 1, MOpt-AFL-ever. - -Have fun with MOpt in AFL! diff --git a/docs/historical_notes.md b/docs/historical_notes.md deleted file mode 100644 index b5d3d157..00000000 --- a/docs/historical_notes.md +++ /dev/null @@ -1,143 +0,0 @@ -# Historical notes - - This doc talks about the rationale of some of the high-level design decisions - for American Fuzzy Lop. It's adopted from a discussion with Rob Graham. - See README.md for the general instruction manual, and technical_details.md for - additional implementation-level insights. - -## 1) Influences - -In short, `afl-fuzz` is inspired chiefly by the work done by Tavis Ormandy back -in 2007. Tavis did some very persuasive experiments using `gcov` block coverage -to select optimal test cases out of a large corpus of data, and then using -them as a starting point for traditional fuzzing workflows. - -(By "persuasive", I mean: netting a significant number of interesting -vulnerabilities.) - -In parallel to this, both Tavis and I were interested in evolutionary fuzzing. -Tavis had his experiments, and I was working on a tool called bunny-the-fuzzer, -released somewhere in 2007. - -Bunny used a generational algorithm not much different from `afl-fuzz`, but -also tried to reason about the relationship between various input bits and -the internal state of the program, with hopes of deriving some additional value -from that. The reasoning / correlation part was probably in part inspired by -other projects done around the same time by Will Drewry and Chris Evans. - -The state correlation approach sounded very sexy on paper, but ultimately, made -the fuzzer complicated, brittle, and cumbersome to use; every other target -program would require a tweak or two. Because Bunny didn't fare a whole lot -better than less sophisticated brute-force tools, I eventually decided to write -it off. You can still find its original documentation at: - - https://code.google.com/p/bunny-the-fuzzer/wiki/BunnyDoc - -There has been a fair amount of independent work, too. Most notably, a few -weeks earlier that year, Jared DeMott had a Defcon presentation about a -coverage-driven fuzzer that relied on coverage as a fitness function. - -Jared's approach was by no means identical to what afl-fuzz does, but it was in -the same ballpark. His fuzzer tried to explicitly solve for the maximum coverage -with a single input file; in comparison, afl simply selects for cases that do -something new (which yields better results - see [technical_details.md](technical_details.md)). - -A few years later, Gabriel Campana released fuzzgrind, a tool that relied purely -on Valgrind and a constraint solver to maximize coverage without any brute-force -bits; and Microsoft Research folks talked extensively about their still -non-public, solver-based SAGE framework. - -In the past six years or so, I've also seen a fair number of academic papers -that dealt with smart fuzzing (focusing chiefly on symbolic execution) and a -couple papers that discussed proof-of-concept applications of genetic -algorithms with the same goals in mind. I'm unconvinced how practical most of -these experiments were; I suspect that many of them suffer from the -bunny-the-fuzzer's curse of being cool on paper and in carefully designed -experiments, but failing the ultimate test of being able to find new, -worthwhile security bugs in otherwise well-fuzzed, real-world software. - -In some ways, the baseline that the "cool" solutions have to compete against is -a lot more impressive than it may seem, making it difficult for competitors to -stand out. For a singular example, check out the work by Gynvael and Mateusz -Jurczyk, applying "dumb" fuzzing to ffmpeg, a prominent and security-critical -component of modern browsers and media players: - - http://googleonlinesecurity.blogspot.com/2014/01/ffmpeg-and-thousand-fixes.html - -Effortlessly getting comparable results with state-of-the-art symbolic execution -in equally complex software still seems fairly unlikely, and hasn't been -demonstrated in practice so far. - -But I digress; ultimately, attribution is hard, and glorying the fundamental -concepts behind AFL is probably a waste of time. The devil is very much in the -often-overlooked details, which brings us to... - -## 2. Design goals for afl-fuzz - -In short, I believe that the current implementation of afl-fuzz takes care of -several itches that seemed impossible to scratch with other tools: - -1) Speed. It's genuinely hard to compete with brute force when your "smart" - approach is resource-intensive. If your instrumentation makes it 10x more - likely to find a bug, but runs 100x slower, your users are getting a bad - deal. - - To avoid starting with a handicap, `afl-fuzz` is meant to let you fuzz most of - the intended targets at roughly their native speed - so even if it doesn't - add value, you do not lose much. - - On top of this, the tool leverages instrumentation to actually reduce the - amount of work in a couple of ways: for example, by carefully trimming the - corpus or skipping non-functional but non-trimmable regions in the input - files. - -2) Rock-solid reliability. It's hard to compete with brute force if your - approach is brittle and fails unexpectedly. Automated testing is attractive - because it's simple to use and scalable; anything that goes against these - principles is an unwelcome trade-off and means that your tool will be used - less often and with less consistent results. - - Most of the approaches based on symbolic execution, taint tracking, or - complex syntax-aware instrumentation are currently fairly unreliable with - real-world targets. Perhaps more importantly, their failure modes can render - them strictly worse than "dumb" tools, and such degradation can be difficult - for less experienced users to notice and correct. - - In contrast, `afl-fuzz` is designed to be rock solid, chiefly by keeping it - simple. In fact, at its core, it's designed to be just a very good - traditional fuzzer with a wide range of interesting, well-researched - strategies to go by. The fancy parts just help it focus the effort in - places where it matters the most. - -3) Simplicity. The author of a testing framework is probably the only person - who truly understands the impact of all the settings offered by the tool - - and who can dial them in just right. Yet, even the most rudimentary fuzzer - frameworks often come with countless knobs and fuzzing ratios that need to - be guessed by the operator ahead of the time. This can do more harm than - good. - - AFL is designed to avoid this as much as possible. The three knobs you - can play with are the output file, the memory limit, and the ability to - override the default, auto-calibrated timeout. The rest is just supposed to - work. When it doesn't, user-friendly error messages outline the probable - causes and workarounds, and get you back on track right away. - -4) Chainability. Most general-purpose fuzzers can't be easily employed - against resource-hungry or interaction-heavy tools, necessitating the - creation of custom in-process fuzzers or the investment of massive CPU - power (most of which is wasted on tasks not directly related to the code - we actually want to test). - - AFL tries to scratch this itch by allowing users to use more lightweight - targets (e.g., standalone image parsing libraries) to create small - corpora of interesting test cases that can be fed into a manual testing - process or a UI harness later on. - -As mentioned in [technical_details.md](technical_details.md), AFL does all this not by systematically -applying a single overarching CS concept, but by experimenting with a variety -of small, complementary methods that were shown to reliably yields results -better than chance. The use of instrumentation is a part of that toolkit, but is -far from being the most important one. - -Ultimately, what matters is that `afl-fuzz` is designed to find cool bugs - and -has a pretty robust track record of doing just that. diff --git a/docs/notes_for_asan.md b/docs/notes_for_asan.md deleted file mode 100644 index f55aeaf2..00000000 --- a/docs/notes_for_asan.md +++ /dev/null @@ -1,157 +0,0 @@ -# Notes for using ASAN with afl-fuzz - - This file discusses some of the caveats for fuzzing under ASAN, and suggests - a handful of alternatives. See README.md for the general instruction manual. - -## 1) Short version - -ASAN on 64-bit systems requests a lot of memory in a way that can't be easily -distinguished from a misbehaving program bent on crashing your system. - -Because of this, fuzzing with ASAN is recommended only in four scenarios: - - - On 32-bit systems, where we can always enforce a reasonable memory limit - (-m 800 or so is a good starting point), - - - On 64-bit systems only if you can do one of the following: - - - Compile the binary in 32-bit mode (gcc -m32), - - - Precisely gauge memory needs using http://jwilk.net/software/recidivm . - - - Limit the memory available to process using cgroups on Linux (see - utils/asan_cgroups). - -To compile with ASAN, set AFL_USE_ASAN=1 before calling 'make clean all'. The -afl-gcc / afl-clang wrappers will pick that up and add the appropriate flags. -Note that ASAN is incompatible with -static, so be mindful of that. - -(You can also use AFL_USE_MSAN=1 to enable MSAN instead.) - -When compiling with AFL_USE_LSAN, the leak sanitizer will normally run -when the program exits. In order to utilize this check at different times, -such as at the end of a loop, you may use the macro __AFL_LEAK_CHECK();. -This macro will report a crash in afl-fuzz if any memory is left leaking -at this stage. You can also use LSAN_OPTIONS and a supressions file -for more fine-tuned checking, however make sure you keep exitcode=23. - -NOTE: if you run several secondary instances, only one should run the target -compiled with ASAN (and UBSAN, CFISAN), the others should run the target with -no sanitizers compiled in. - -There is also the option of generating a corpus using a non-ASAN binary, and -then feeding it to an ASAN-instrumented one to check for bugs. This is faster, -and can give you somewhat comparable results. You can also try using -libdislocator (see [utils/libdislocator/README.dislocator.md](../utils/libdislocator/README.dislocator.md) in the parent directory) as a -lightweight and hassle-free (but less thorough) alternative. - -## 2) Long version - -ASAN allocates a huge region of virtual address space for bookkeeping purposes. -Most of this is never actually accessed, so the OS never has to allocate any -real pages of memory for the process, and the VM grabbed by ASAN is essentially -"free" - but the mapping counts against the standard OS-enforced limit -(RLIMIT_AS, aka ulimit -v). - -On our end, afl-fuzz tries to protect you from processes that go off-rails -and start consuming all the available memory in a vain attempt to parse a -malformed input file. This happens surprisingly often, so enforcing such a limit -is important for almost any fuzzer: the alternative is for the kernel OOM -handler to step in and start killing random processes to free up resources. -Needless to say, that's not a very nice prospect to live with. - -Unfortunately, un*x systems offer no portable way to limit the amount of -pages actually given to a process in a way that distinguishes between that -and the harmless "land grab" done by ASAN. In principle, there are three standard -ways to limit the size of the heap: - - - The RLIMIT_AS mechanism (ulimit -v) caps the size of the virtual space - - but as noted, this pays no attention to the number of pages actually - in use by the process, and doesn't help us here. - - - The RLIMIT_DATA mechanism (ulimit -d) seems like a good fit, but it applies - only to the traditional sbrk() / brk() methods of requesting heap space; - modern allocators, including the one in glibc, routinely rely on mmap() - instead, and circumvent this limit completely. - - - Finally, the RLIMIT_RSS limit (ulimit -m) sounds like what we need, but - doesn't work on Linux - mostly because nobody felt like implementing it. - -There are also cgroups, but they are Linux-specific, not universally available -even on Linux systems, and they require root permissions to set up; I'm a bit -hesitant to make afl-fuzz require root permissions just for that. That said, -if you are on Linux and want to use cgroups, check out the contributed script -that ships in utils/asan_cgroups/. - -In settings where cgroups aren't available, we have no nice, portable way to -avoid counting the ASAN allocation toward the limit. On 32-bit systems, or for -binaries compiled in 32-bit mode (-m32), this is not a big deal: ASAN needs -around 600-800 MB or so, depending on the compiler - so all you need to do is -to specify -m that is a bit higher than that. - -On 64-bit systems, the situation is more murky, because the ASAN allocation -is completely outlandish - around 17.5 TB in older versions, and closer to -20 TB with newest ones. The actual amount of memory on your system is -(probably!) just a tiny fraction of that - so unless you dial the limit -with surgical precision, you will get no protection from OOM bugs. - -On my system, the amount of memory grabbed by ASAN with a slightly older -version of gcc is around 17,825,850 MB; for newest clang, it's 20,971,600. -But there is no guarantee that these numbers are stable, and if you get them -wrong by "just" a couple gigs or so, you will be at risk. - -To get the precise number, you can use the recidivm tool developed by Jakub -Wilk (http://jwilk.net/software/recidivm). In absence of this, ASAN is *not* -recommended when fuzzing 64-bit binaries, unless you are confident that they -are robust and enforce reasonable memory limits (in which case, you can -specify '-m none' when calling afl-fuzz). - -Using recidivm or running with no limits aside, there are two other decent -alternatives: build a corpus of test cases using a non-ASAN binary, and then -examine them with ASAN, Valgrind, or other heavy-duty tools in a more -controlled setting; or compile the target program with -m32 (32-bit mode) -if your system supports that. - -## 3) Interactions with the QEMU mode - -ASAN, MSAN, and other sanitizers appear to be incompatible with QEMU user -emulation, so please do not try to use them with the -Q option; QEMU doesn't -seem to appreciate the shadow VM trick used by these tools, and will likely -just allocate all your physical memory, then crash. - -You can, however, use QASan to run binaries that are not instrumented with ASan -under QEMU with the AFL++ instrumentation. - -https://github.com/andreafioraldi/qasan - -## 4) ASAN and OOM crashes - -By default, ASAN treats memory allocation failures as fatal errors, immediately -causing the program to crash. Since this is a departure from normal POSIX -semantics (and creates the appearance of security issues in otherwise -properly-behaving programs), we try to disable this by specifying -allocator_may_return_null=1 in ASAN_OPTIONS. - -Unfortunately, it's been reported that this setting still causes ASAN to -trigger phantom crashes in situations where the standard allocator would -simply return NULL. If this is interfering with your fuzzing jobs, you may -want to cc: yourself on this bug: - - https://bugs.llvm.org/show_bug.cgi?id=22026 - -## 5) What about UBSAN? - -New versions of UndefinedBehaviorSanitizer offers the --fsanitize=undefined-trap-on-error compiler flag that tells UBSan to insert an -istruction that will cause SIGILL (ud2 on x86) when an undefined behaviour -is detected. This is the option that you want to use when combining AFL++ -and UBSan. - -AFL_USE_UBSAN=1 env var will add this compiler flag to afl-clang-fast, -afl-gcc-fast and afl-gcc for you. - -Old versions of UBSAN don't offer a consistent way -to abort() on fault conditions or to terminate with a distinctive exit code -but there are some versions of the library can be binary-patched to address this -issue. You can also preload a shared library that substitute all the UBSan -routines used to report errors with abort(). diff --git a/docs/perf_tips.md b/docs/perf_tips.md index c5968206..7c14cbbc 100644 --- a/docs/perf_tips.md +++ b/docs/perf_tips.md @@ -48,13 +48,9 @@ be then manually fed to a more resource-hungry program later on. Also note that reading the fuzzing input via stdin is faster than reading from a file. -## 3. Use LLVM instrumentation +## 3. Use LLVM persistent instrumentation -When fuzzing slow targets, you can gain 20-100% performance improvement by -using the LLVM-based instrumentation mode described in [the instrumentation README](../instrumentation/README.llvm.md). -Note that this mode requires the use of clang and will not work with GCC. - -The LLVM mode also offers a "persistent", in-process fuzzing mode that can +The LLVM mode offers a "persistent", in-process fuzzing mode that can work well for certain types of self-contained libraries, and for fast targets, can offer performance gains up to 5-10x; and a "deferred fork server" mode that can offer huge benefits for programs with high startup overhead. Both @@ -138,8 +134,7 @@ misses, or similar factors, but they are less likely to be a concern.) ## 7. Keep memory use and timeouts in check -If you have increased the `-m` or `-t` limits more than truly necessary, consider -dialing them back down. +Consider setting low values for -m and -t. For programs that are nominally very fast, but get sluggish for some inputs, you can also try setting `-t` values that are more punishing than what `afl-fuzz` @@ -164,6 +159,20 @@ There are several OS-level factors that may affect fuzzing speed: - Network filesystems, either used for fuzzer input / output, or accessed by the fuzzed binary to read configuration files (pay special attention to the home directory - many programs search it for dot-files). + - Disable all the spectre, meltdown etc. security countermeasures in the + kernel if your machine is properly separated: + +``` +ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off +no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable +nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off +spectre_v2=off stf_barrier=off +``` + In most Linux distributions you can put this into a `/etc/default/grub` + variable. + +The following list of changes are made when executing `afl-system-config`: + - On-demand CPU scaling. The Linux `ondemand` governor performs its analysis on a particular schedule and is known to underestimate the needs of short-lived processes spawned by `afl-fuzz` (or any other fuzzer). On Linux, @@ -196,26 +205,4 @@ There are several OS-level factors that may affect fuzzing speed: Setting a different scheduling policy for the fuzzer process - say `SCHED_RR` - can usually speed things up, too, but needs to be done with care. - - Use the `afl-system-config` script to set all proc/sys settings above in one go. - - Disable all the spectre, meltdown etc. security countermeasures in the - kernel if your machine is properly separated: - -``` -ibpb=off ibrs=off kpti=off l1tf=off mds=off mitigations=off -no_stf_barrier noibpb noibrs nopcid nopti nospec_store_bypass_disable -nospectre_v1 nospectre_v2 pcid=off pti=off spec_store_bypass_disable=off -spectre_v2=off stf_barrier=off -``` - In most Linux distributions you can put this into a `/etc/default/grub` - variable. - -## 9. If all other options fail, use `-d` - -For programs that are genuinely slow, in cases where you really can't escape -using huge input files, or when you simply want to get quick and dirty results -early on, you can always resort to the `-d` mode. -The mode causes `afl-fuzz` to skip all the deterministic fuzzing steps, which -makes output a lot less neat and can ultimately make the testing a bit less -in-depth, but it will give you an experience more familiar from other fuzzing -tools. diff --git a/docs/power_schedules.md b/docs/power_schedules.md deleted file mode 100644 index 493f9609..00000000 --- a/docs/power_schedules.md +++ /dev/null @@ -1,32 +0,0 @@ -# afl++'s power schedules based on AFLfast - - -Power schedules implemented by Marcel Böhme \. -AFLFast is an extension of AFL which is written and maintained by -Michal Zalewski \. - -AFLfast has helped in the success of Team Codejitsu at the finals of the DARPA Cyber Grand Challenge where their bot Galactica took **2nd place** in terms of #POVs proven (see red bar at https://www.cybergrandchallenge.com/event#results). AFLFast exposed several previously unreported CVEs that could not be exposed by AFL in 24 hours and otherwise exposed vulnerabilities significantly faster than AFL while generating orders of magnitude more unique crashes. - -Essentially, we observed that most generated inputs exercise the same few "high-frequency" paths and developed strategies to gravitate towards low-frequency paths, to stress significantly more program behavior in the same amount of time. We devised several **search strategies** that decide in which order the seeds should be fuzzed and **power schedules** that smartly regulate the number of inputs generated from a seed (i.e., the time spent fuzzing a seed). We call the number of inputs generated from a seed, the seed's **energy**. - -We find that AFL's exploitation-based constant schedule assigns **too much energy to seeds exercising high-frequency paths** (e.g., paths that reject invalid inputs) and not enough energy to seeds exercising low-frequency paths (e.g., paths that stress interesting behaviors). Technically, we modified the computation of a seed's performance score (`calculate_score`), which seed is marked as favourite (`update_bitmap_score`), and which seed is chosen next from the circular queue (`main`). We implemented the following schedules (in the order of their effectiveness, best first): - -| AFL flag | Power Schedule | -| ------------- | -------------------------- | -| `-p explore` | ![EXPLORE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D) | -| `-p fast` (default)| ![FAST](http://latex.codecogs.com/gif.latex?p(i)=\\min\\left(\\frac{\\alpha(i)}{\\beta}\\cdot\\frac{2^{s(i)}}{f(i)},M\\right)) | -| `-p coe` | ![COE](http://latex.codecogs.com/gif.latex?p%28i%29%3D%5Cbegin%7Bcases%7D%200%20%26%20%5Ctext%7B%20if%20%7D%20f%28i%29%20%3E%20%5Cmu%5C%5C%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%202%5E%7Bs%28i%29%7D%2C%20M%5Cright%29%20%26%20%5Ctext%7B%20otherwise.%7D%20%5Cend%7Bcases%7D) | -| `-p quad` | ![QUAD](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%5E2%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p lin` | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Cmin%5Cleft%28%5Cfrac%7B%5Calpha%28i%29%7D%7B%5Cbeta%7D%5Ccdot%5Cfrac%7Bs%28i%29%7D%7Bf%28i%29%7D%2CM%5Cright%29) | -| `-p exploit` (AFL) | ![LIN](http://latex.codecogs.com/gif.latex?p%28i%29%20%3D%20%5Calpha%28i%29) | -| `-p mmopt` | Experimental: `explore` with no weighting to runtime and increased weighting on the last 5 queue entries | -| `-p rare` | Experimental: `rare` puts focus on queue entries that hit rare edges | -| `-p seek` | Experimental: `seek` is EXPLORE but ignoring the runtime of the queue input and less focus on the size | -where *α(i)* is the performance score that AFL uses to compute for the seed input *i*, *β(i)>1* is a constant, *s(i)* is the number of times that seed *i* has been chosen from the queue, *f(i)* is the number of generated inputs that exercise the same path as seed *i*, and *μ* is the average number of generated inputs exercising a path. - -More details can be found in the paper that was accepted at the [23rd ACM Conference on Computer and Communications Security (CCS'16)](https://www.sigsac.org/ccs/CCS2016/accepted-papers/). - -PS: In parallel mode (several instances with shared queue), we suggest to run the main node using the exploit schedule (-p exploit) and the secondary nodes with a combination of cut-off-exponential (-p coe), exponential (-p fast; default), and explore (-p explore) schedules. In single mode, the default settings will do. **EDIT:** In parallel mode, AFLFast seems to perform poorly because the path probability estimates are incorrect for the imported seeds. Pull requests to fix this issue by syncing the estimates across instances are appreciated :) - -Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. -Released under terms and conditions of Apache License, Version 2.0. diff --git a/docs/technical_details.md b/docs/technical_details.md index a0453c91..6a4660a2 100644 --- a/docs/technical_details.md +++ b/docs/technical_details.md @@ -1,5 +1,9 @@ # Technical "whitepaper" for afl-fuzz + +NOTE: this document is rather outdated! + + This document provides a quick overview of the guts of American Fuzzy Lop. See README.md for the general instruction manual; and for a discussion of motivations and design goals behind AFL, see historical_notes.md. diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index 3f518b55..b01ea987 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -299,8 +299,9 @@ static void __afl_map_shm(void) { if (!getenv("AFL_QUIET")) fprintf(stderr, - "Warning: AFL++ tools will need to set AFL_MAP_SIZE to %u " - "to be able to run this instrumented program!\n", + "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u " + "to be able to run this instrumented program if this " + "crashes!\n", __afl_final_loc); } -- cgit 1.4.1 From 4fe572b80f76ff0b0e916b639d1e04d5af48b157 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 12:24:29 +0200 Subject: always build aflpp driver --- GNUmakefile | 3 +-- docs/Changelog.md | 1 + utils/aflpp_driver/GNUmakefile | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'docs/Changelog.md') diff --git a/GNUmakefile b/GNUmakefile index 53cc0537..7a1ba88a 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -306,6 +306,7 @@ endif .PHONY: all all: test_x86 test_shm test_python ready $(PROGS) afl-as llvm gcc_plugin test_build all_done + -$(MAKE) -C utils/aflpp_driver .PHONY: llvm llvm: @@ -597,7 +598,6 @@ distrib: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C utils/libdislocator $(MAKE) -C utils/libtokencap - -$(MAKE) -C utils/aflpp_driver $(MAKE) -C utils/afl_network_proxy $(MAKE) -C utils/socket_fuzzing $(MAKE) -C utils/argv_fuzzing @@ -622,7 +622,6 @@ source-only: all -$(MAKE) -f GNUmakefile.gcc_plugin $(MAKE) -C utils/libdislocator $(MAKE) -C utils/libtokencap - -$(MAKE) -C utils/aflpp_driver %.8: % @echo .TH $* 8 $(BUILD_DATE) "afl++" > $@ diff --git a/docs/Changelog.md b/docs/Changelog.md index 705daa40..29af44ab 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -36,6 +36,7 @@ sending a mail to . - fix timeout handling - add forkserver support for better performance - ensure afl-compiler-rt is built for gcc_module + - always build aflpp_driver for libfuzzer harnesses - added `AFL_NO_FORKSRV` env variable support to afl-cmin, afl-tmin, and afl-showmap, by @jhertz - removed outdated documents, improved existing documentation diff --git a/utils/aflpp_driver/GNUmakefile b/utils/aflpp_driver/GNUmakefile index ad99b893..c282a9f3 100644 --- a/utils/aflpp_driver/GNUmakefile +++ b/utils/aflpp_driver/GNUmakefile @@ -15,28 +15,28 @@ aflpp_driver.o: aflpp_driver.c -$(LLVM_BINDIR)clang -I. -I../../include $(CFLAGS) -c aflpp_driver.c libAFLDriver.a: aflpp_driver.o - ar ru libAFLDriver.a aflpp_driver.o - cp -vf libAFLDriver.a ../../ + @ar rc libAFLDriver.a aflpp_driver.o + @cp -vf libAFLDriver.a ../../ debug: $(LLVM_BINDIR)clang -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.o ../../src/afl-performance.c $(LLVM_BINDIR)clang -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c #$(LLVM_BINDIR)clang -S -emit-llvm -Wno-deprecated -I../../include $(CFLAGS) -D_DEBUG=\"1\" -c -o afl-performance.ll ../../src/afl-performance.c #$(LLVM_BINDIR)clang -S -emit-llvm -I../../include -D_DEBUG=\"1\" -g -funroll-loops -c aflpp_driver.c - ar ru libAFLDriver.a afl-performance.o aflpp_driver.o + ar rc libAFLDriver.a afl-performance.o aflpp_driver.o aflpp_qemu_driver.o: aflpp_qemu_driver.c -$(LLVM_BINDIR)clang $(CFLAGS) -O0 -funroll-loops -c aflpp_qemu_driver.c libAFLQemuDriver.a: aflpp_qemu_driver.o - -ar ru libAFLQemuDriver.a aflpp_qemu_driver.o - -cp -vf libAFLQemuDriver.a ../../ + @-ar rc libAFLQemuDriver.a aflpp_qemu_driver.o + @-cp -vf libAFLQemuDriver.a ../../ aflpp_qemu_driver_hook.so: aflpp_qemu_driver_hook.o - -test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." + @-test -e aflpp_qemu_driver_hook.o && $(LLVM_BINDIR)clang -shared aflpp_qemu_driver_hook.o -o aflpp_qemu_driver_hook.so || echo "Note: Optional aflpp_qemu_driver_hook.so not built." aflpp_qemu_driver_hook.o: aflpp_qemu_driver_hook.c - -test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." + @-test -e ../../qemu_mode/qemuafl/qemuafl/api.h && $(LLVM_BINDIR)clang $(CFLAGS) -funroll-loops -c aflpp_qemu_driver_hook.c || echo "Note: Optional aflpp_qemu_driver_hook.o not built." test: debug #clang -S -emit-llvm -D_DEBUG=\"1\" -I../../include -Wl,--allow-multiple-definition -funroll-loops -o aflpp_driver_test.ll aflpp_driver_test.c -- cgit 1.4.1 From 9ec63d3f1776ae1442fe89d5e076b58b36997f76 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 14 Jul 2021 14:31:27 +0200 Subject: fix frida, fix dictionary generation to honor AFL_LLVM_{ALLOW/DENY}LIST --- docs/Changelog.md | 2 ++ frida_mode/src/instrument/instrument.c | 3 ++- instrumentation/SanitizerCoverageLTO.so.cc | 2 ++ instrumentation/afl-llvm-dict2file.so.cc | 1 + instrumentation/afl-llvm-pass.so.cc | 4 ++-- 5 files changed, 9 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 29af44ab..8aca5608 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -24,10 +24,12 @@ sending a mail to . - Fix to instrument global namespace functions in c++ - Fix for llvm 13 - support partial linking + - do honor AFL_LLVM_{ALLOW/DENY}LIST for LTO autodictionary and DICT2FILE - We do support llvm versions from 3.8 to 5.0 again - frida_mode: - several fixes for cmplog - remove need for AFL_FRIDA_PERSISTENT_RETADDR_OFFSET + - less coverage collision - feature parity of aarch64 with intel now (persistent, cmplog, in-memory testcases, asan) - afl-cmin and afl-showmap -i do now descend into subdirectories diff --git a/frida_mode/src/instrument/instrument.c b/frida_mode/src/instrument/instrument.c index 81d14013..e1dabf92 100644 --- a/frida_mode/src/instrument/instrument.c +++ b/frida_mode/src/instrument/instrument.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "frida-gumjs.h" @@ -289,7 +290,7 @@ void instrument_init(void) { * needs to be different for each instance. */ instrument_hash_seed = - g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ gettid(); + g_get_monotonic_time() ^ (((guint64)getpid()) << 32) ^ syscall(SYS_gettid); OKF("Instrumentation - seed [0x%016" G_GINT64_MODIFIER "x]", instrument_hash_seed); diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 28eb0b9f..91b81910 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -516,6 +516,8 @@ bool ModuleSanitizerCoverage::instrumentModule( for (auto &F : M) { + if (!isInInstrumentList(&F) || !F.size()) { continue; } + for (auto &BB : F) { for (auto &IN : BB) { diff --git a/instrumentation/afl-llvm-dict2file.so.cc b/instrumentation/afl-llvm-dict2file.so.cc index 5350f62b..9daa75a8 100644 --- a/instrumentation/afl-llvm-dict2file.so.cc +++ b/instrumentation/afl-llvm-dict2file.so.cc @@ -154,6 +154,7 @@ bool AFLdict2filePass::runOnModule(Module &M) { for (auto &F : M) { if (isIgnoreFunction(&F)) continue; + if (!isInInstrumentList(&F) || !F.size()) { continue; } /* Some implementation notes. * diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 94b77f7d..ecf28f31 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -438,9 +438,9 @@ bool AFLCoverage::runOnModule(Module &M) { fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(), F.size()); - if (!isInInstrumentList(&F)) continue; + if (!isInInstrumentList(&F)) { continue; } - if (F.size() < function_minimum_size) continue; + if (F.size() < function_minimum_size) { continue; } std::list todo; for (auto &BB : F) { -- cgit 1.4.1 From 6f03749c734e535cf9488027c692a7ee2591b60f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 15 Jul 2021 16:27:40 +0200 Subject: ammend changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/Changelog.md') diff --git a/docs/Changelog.md b/docs/Changelog.md index 8aca5608..7131360a 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -12,11 +12,13 @@ sending a mail to . - afl-fuzz: - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs + - fix for AFLfast schedule counting - removed implied -D determinstic from -M main - if the target becomes unavailable check out out/default/error.txt for an indicator why - AFL_CAL_FAST was a dead env, now does the same as AFL_FAST_CAL - reverse read the queue on resumes (more effective) + - fix custom mutator trimming - afl-cc: - Update to COMPCOV/laf-intel that speeds up the instrumentation process a lot - thanks to Michael Rodler/f0rki for the PR! -- cgit 1.4.1 From 18fd97fc5ffc5ad94e735cfbfa0d500463dcb585 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 19 Jul 2021 09:12:24 +0200 Subject: v3.14c release --- README.md | 9 +++++++-- docs/Changelog.md | 2 +- utils/qbdi_mode/README.md | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'docs/Changelog.md') diff --git a/README.md b/README.md index 37fd90e3..94a38ab1 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ AFL++ Logo - Release Version: [3.13c](https://github.com/AFLplusplus/AFLplusplus/releases) + Release Version: [3.14c](https://github.com/AFLplusplus/AFLplusplus/releases) - Github Version: 3.14a + Github Version: 3.15a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) @@ -31,6 +31,11 @@ With afl++ 3.13-3.20 we introduce frida_mode (-O) to have an alternative for binary-only fuzzing. It is slower than Qemu mode but works on MacOS, Android, iOS etc. +With afl++ 3.15 we introduced the following changes from previous behaviours: + * Also -M main mode does not due deterministic fuzzing by default anymore + * afl-cmin and afl-showmap -Ci now descent into subdirectories like + afl-fuzz -i does (but note that afl-cmin.bash does not) + With afl++ 3.14 we introduced the following changes from previous behaviours: * afl-fuzz: deterministic fuzzing it not a default for -M main anymore * afl-cmin/afl-showmap -i now descends into subdirectories (afl-cmin.bash diff --git a/docs/Changelog.md b/docs/Changelog.md index 7131360a..fcfd2ce8 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -8,7 +8,7 @@ Want to stay in the loop on major new features? Join our mailing list by sending a mail to . -### Version ++3.14a (release) +### Version ++3.14c (release) - afl-fuzz: - fix -F when a '/' was part of the parameter - fixed a crash for cmplog for very slow inputs diff --git a/utils/qbdi_mode/README.md b/utils/qbdi_mode/README.md index 641a6e85..cf5d3359 100755 --- a/utils/qbdi_mode/README.md +++ b/utils/qbdi_mode/README.md @@ -1,5 +1,9 @@ # qbdi-based binary-only instrumentation for afl-fuzz +NOTE: this code is outdated and first would need to be adapted to the current +afl++ versions first. +Try afl_frida or fpicker [https://github.com/ttdennis/fpicker/](https://github.com/ttdennis/fpicker/) first, maybe they suite your need. + ## 1) Introduction The code in ./qbdi_mode allows you to build a standalone feature that -- cgit 1.4.1