From 00e54565ef109a6c697db77b19d1618e37092125 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 17 Apr 2021 21:29:50 +0200 Subject: [PATCH 1/9] use atomic read-modify-write increment for LLVM CLASSIC --- instrumentation/afl-llvm-pass.so.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 0f773aba..70480ff9 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -388,7 +388,6 @@ bool AFLCoverage::runOnModule(Module &M) { #endif // other constants we need - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); ConstantInt *One = ConstantInt::get(Int8Ty, 1); Value * PrevCtx = NULL; // CTX sensitive coverage @@ -628,6 +627,10 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ +#if 1 /* Atomic */ + 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)); @@ -651,6 +654,7 @@ bool AFLCoverage::runOnModule(Module &M) { * Counter + OverflowFlag -> Counter */ + ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); auto cf = IRB.CreateICmpEQ(Incr, Zero); auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); @@ -660,6 +664,8 @@ bool AFLCoverage::runOnModule(Module &M) { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); +#endif /* 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) */ From ec49c7fbf5b5dd2259ebfd4a92f6aad5b333c328 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sat, 17 Apr 2021 22:32:33 +0200 Subject: [PATCH 2/9] Change other LLVM modes to atomic increments --- instrumentation/SanitizerCoverageLTO.so.cc | 6 +++++- instrumentation/SanitizerCoveragePCGUARD.so.cc | 8 +++++++- instrumentation/afl-llvm-lto-instrumentation.so.cc | 6 ++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 6dd390e6..cd6b1939 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1496,7 +1496,11 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ +#if 1 /* Atomic */ + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); +#else LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); @@ -1512,7 +1516,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); - +#endif // done :) inst++; diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 09cda9e2..dd2e1459 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1080,6 +1080,12 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, /* Load counter for CurLoc */ Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); + +#if 1 /* Atomic */ + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); + +#else LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); /* Update bitmap */ @@ -1095,7 +1101,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } IRB.CreateStore(Incr, MapPtrIdx); - +#endif // done :) // IRB.CreateCall(SanCovTracePCGuard, Offset)->setCannotMerge(); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index f6cdbe9e..5ed13ff0 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -839,6 +839,11 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ +#if 1 /* Atomic */ + 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)); @@ -855,6 +860,7 @@ bool AFLLTOPass::runOnModule(Module &M) { IRB.CreateStore(Incr, MapPtrIdx) ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); +#endif // done :) From 976969dce56cb7d8349706962eb774a0ab0a0931 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Wed, 28 Apr 2021 00:29:15 +0200 Subject: [PATCH 3/9] work in progress: not working correctly yet --- instrumentation/afl-llvm-pass.so.cc | 79 ++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 70480ff9..6c898c48 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -409,8 +409,14 @@ bool AFLCoverage::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; + unsigned extra_increment_BB = 0; for (auto &BB : F) { + if (extra_increment_BB) { + // increment BB + --extra_increment_BB; + continue; + } BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); @@ -628,7 +634,78 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ #if 1 /* Atomic */ - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); +#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 + if (!skip_nozero) { + +#endif + /* hexcoder: Realize a 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 + */ + + // C: unsigned char old = atomic_load_explicit(MapPtrIdx, memory_order_relaxed); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setAlignment(llvm::Align()); + Counter->setAtomic(llvm::AtomicOrdering::Monotonic); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + // 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 + BasicBlock::iterator it(*Counter); it++; + BasicBlock * end_bb = BB.splitBasicBlock(it); + + extra_increment_BB = 2; + // insert the block before the second half of the split + BasicBlock * do_while_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + + // set terminator of BB from target end_bb to target do_while_bb + auto term = BB.getTerminator(); + BranchInst::Create(do_while_bb, &BB); + term->eraseFromParent(); + + auto saved = IRB.saveIP(); + IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); + + PHINode * PN = IRB.CreatePHI(Int8Ty, 2); + + auto * Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + + Value *Incr = IRB.CreateAdd(Counter, One); + + auto * Select = IRB.CreateSelect(Cmp, One, Incr); + + auto * CmpXchg = IRB.CreateAtomicCmpXchg(MapPtrIdx, PN, Select, + llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic); + CmpXchg->setAlignment(llvm::Align()); + CmpXchg->setWeak(true); + CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + Value * Success = IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); + Value * OldVal = IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); + + PN->addIncoming(Counter, &BB); + PN->addIncoming(OldVal, do_while_bb); + +// term = do_while_bb->getTerminator(); + +// BranchInst::Create(/*true*/end_bb, /*false*/do_while_bb, Success, do_while_bb); + IRB.CreateCondBr(Success, end_bb, do_while_bb); +// BranchInst::Create(end_bb, do_while_bb); +// term->eraseFromParent(); + IRB.restoreIP(saved); + + } else { + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } #else LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); From b15fcde477d4c1d59265c717841b5942143917ee Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 30 Apr 2021 12:09:06 +0200 Subject: [PATCH 4/9] still not working --- instrumentation/afl-llvm-pass.so.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 6c898c48..27b53e68 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -409,12 +409,9 @@ bool AFLCoverage::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; - unsigned extra_increment_BB = 0; for (auto &BB : F) { - if (extra_increment_BB) { - // increment BB - --extra_increment_BB; + if (BB.getName() == "injected") { continue; } BasicBlock::iterator IP = BB.getFirstInsertionPt(); @@ -662,8 +659,8 @@ bool AFLCoverage::runOnModule(Module &M) { // the calculation may need to repeat, if atomic compare_exchange is not successful BasicBlock::iterator it(*Counter); it++; BasicBlock * end_bb = BB.splitBasicBlock(it); + end_bb->setName("injected"); - extra_increment_BB = 2; // insert the block before the second half of the split BasicBlock * do_while_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); From 70e2737222ee49ca5375f42ab51a858f9b75d5cb Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Thu, 6 May 2021 21:11:37 +0200 Subject: [PATCH 5/9] first working NeverZero implementation --- instrumentation/afl-llvm-pass.so.cc | 132 +++++++++++++++------------- 1 file changed, 69 insertions(+), 63 deletions(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 27b53e68..1ee946e5 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -409,11 +409,9 @@ bool AFLCoverage::runOnModule(Module &M) { if (F.size() < function_minimum_size) continue; + std::list todo; for (auto &BB : F) { - if (BB.getName() == "injected") { - continue; - } BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); @@ -639,66 +637,8 @@ bool AFLCoverage::runOnModule(Module &M) { if (!skip_nozero) { #endif - /* hexcoder: Realize a 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 - */ - - // C: unsigned char old = atomic_load_explicit(MapPtrIdx, memory_order_relaxed); - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setAlignment(llvm::Align()); - Counter->setAtomic(llvm::AtomicOrdering::Monotonic); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - // 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 - BasicBlock::iterator it(*Counter); it++; - BasicBlock * end_bb = BB.splitBasicBlock(it); - end_bb->setName("injected"); - - // insert the block before the second half of the split - BasicBlock * do_while_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - - // set terminator of BB from target end_bb to target do_while_bb - auto term = BB.getTerminator(); - BranchInst::Create(do_while_bb, &BB); - term->eraseFromParent(); - - auto saved = IRB.saveIP(); - IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); - - PHINode * PN = IRB.CreatePHI(Int8Ty, 2); - - auto * Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); - - Value *Incr = IRB.CreateAdd(Counter, One); - - auto * Select = IRB.CreateSelect(Cmp, One, Incr); - - auto * CmpXchg = IRB.CreateAtomicCmpXchg(MapPtrIdx, PN, Select, - llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic); - CmpXchg->setAlignment(llvm::Align()); - CmpXchg->setWeak(true); - CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - - Value * Success = IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); - Value * OldVal = IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); - - PN->addIncoming(Counter, &BB); - PN->addIncoming(OldVal, do_while_bb); - -// term = do_while_bb->getTerminator(); - -// BranchInst::Create(/*true*/end_bb, /*false*/do_while_bb, Success, do_while_bb); - IRB.CreateCondBr(Success, end_bb, do_while_bb); -// BranchInst::Create(end_bb, do_while_bb); -// term->eraseFromParent(); - IRB.restoreIP(saved); + // register MapPtrIdx in a todo list + todo.push_back(MapPtrIdx); } else { IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); @@ -795,6 +735,72 @@ bool AFLCoverage::runOnModule(Module &M) { } +#if 1 /*Atomic NeverZero */ + // handle the todo list + for (auto val : todo) { + /* hexcoder: Realize a 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 + */ + + // C: unsigned char old = atomic_load_explicit(MapPtrIdx, memory_order_relaxed); + Value * MapPtrIdx = val; + Instruction * MapPtrIdxInst = cast(val); + BasicBlock::iterator it0(&(*MapPtrIdxInst)); + ++it0; + IRBuilder<> IRB(&(*it0)); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setAlignment(llvm::Align()); + Counter->setAtomic(llvm::AtomicOrdering::Monotonic); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + 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 + BasicBlock::iterator it(*Counter); it++; + BasicBlock * end_bb = BB->splitBasicBlock(it); + end_bb->setName("injected"); + + // insert the block before the second half of the split + BasicBlock * do_while_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + + // set terminator of BB from target end_bb to target do_while_bb + auto term = BB->getTerminator(); + BranchInst::Create(do_while_bb, BB); + term->eraseFromParent(); + + IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); + + PHINode * PN = IRB.CreatePHI(Int8Ty, 2); + + auto * Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + + Value *Incr = IRB.CreateAdd(Counter, One); + + auto * Select = IRB.CreateSelect(Cmp, One, Incr); + + auto * CmpXchg = IRB.CreateAtomicCmpXchg(MapPtrIdx, PN, Select, + llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic); + CmpXchg->setAlignment(llvm::Align()); + CmpXchg->setWeak(true); + CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + + Value * Success = IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); + Value * OldVal = IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); + + PN->addIncoming(Counter, BB); + PN->addIncoming(OldVal, do_while_bb); + + IRB.CreateCondBr(Success, end_bb, do_while_bb); + + } +#endif + } /* From 32be08d7b31cb004f34d3ef2d3916ca0e4531765 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Fri, 7 May 2021 08:13:50 +0200 Subject: [PATCH 6/9] add some comments --- instrumentation/afl-llvm-pass.so.cc | 34 ++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 1ee946e5..53e076ff 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -738,7 +738,8 @@ bool AFLCoverage::runOnModule(Module &M) { #if 1 /*Atomic NeverZero */ // handle the todo list for (auto val : todo) { - /* hexcoder: Realize a counter that skips zero during overflow. + + /* 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 @@ -748,12 +749,28 @@ bool AFLCoverage::runOnModule(Module &M) { * Counter + OverflowFlag -> Counter */ - // C: unsigned char old = atomic_load_explicit(MapPtrIdx, memory_order_relaxed); + /* equivalent c code looks like this + * Thanks to https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ + + 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)); + + */ + Value * MapPtrIdx = val; Instruction * MapPtrIdxInst = cast(val); BasicBlock::iterator it0(&(*MapPtrIdxInst)); ++it0; IRBuilder<> IRB(&(*it0)); + + // load the old counter value atomically LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); Counter->setAlignment(llvm::Align()); Counter->setAtomic(llvm::AtomicOrdering::Monotonic); @@ -762,7 +779,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 - BasicBlock::iterator it(*Counter); it++; + + BasicBlock::iterator it(*Counter); it++; // split after load counter BasicBlock * end_bb = BB->splitBasicBlock(it); end_bb->setName("injected"); @@ -774,28 +792,38 @@ bool AFLCoverage::runOnModule(Module &M) { BranchInst::Create(do_while_bb, BB); term->eraseFromParent(); + // continue to fill instructions into the do_while loop IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); PHINode * PN = IRB.CreatePHI(Int8Ty, 2); + // compare with maximum value 0xff auto * Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + // increment the counter Value *Incr = IRB.CreateAdd(Counter, One); + // select the counter value or 1 auto * Select = IRB.CreateSelect(Cmp, One, Incr); + // try to save back the new counter value auto * CmpXchg = IRB.CreateAtomicCmpXchg(MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic); CmpXchg->setAlignment(llvm::Align()); CmpXchg->setWeak(true); CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + // get the result of trying to update the Counter Value * Success = IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); + // get the (possibly updated) value of Counter Value * OldVal = IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); + // initially we use Counter PN->addIncoming(Counter, BB); + // on retry, we use the updated value PN->addIncoming(OldVal, do_while_bb); + // if the cmpXchg was not successful, retry IRB.CreateCondBr(Success, end_bb, do_while_bb); } From c9539aa6b7fb4b9d2dae6c65446c525375388c2f Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 30 May 2021 11:45:11 +0200 Subject: [PATCH 7/9] support new env var AFL_LLVM_THREADSAFE_INST to enable atomic counters. add new test case for that. --- include/envs.h | 1 + instrumentation/afl-llvm-pass.so.cc | 249 +++++++++++++++------------- test/test-llvm.sh | 30 ++++ 3 files changed, 168 insertions(+), 112 deletions(-) diff --git a/include/envs.h b/include/envs.h index ebe98257..e6f6d7c9 100644 --- a/include/envs.h +++ b/include/envs.h @@ -114,6 +114,7 @@ static char *afl_environment_variables[] = { "AFL_NGRAM_SIZE", "AFL_LLVM_NOT_ZERO", "AFL_LLVM_INSTRUMENT_FILE", + "AFL_LLVM_THREADSAFE_INST", "AFL_LLVM_SKIP_NEVERZERO", "AFL_NO_AFFINITY", "AFL_LLVM_LTO_STARTID", diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 53e076ff..3b1119fc 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -86,6 +86,7 @@ class AFLCoverage : public ModulePass { uint32_t map_size = MAP_SIZE; uint32_t function_minimum_size = 1; char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + char * use_threadsafe_counters = nullptr; }; @@ -182,6 +183,19 @@ bool AFLCoverage::runOnModule(Module &M) { char *neverZero_counters_str = getenv("AFL_LLVM_NOT_ZERO"); #endif skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + + if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { + + if (use_threadsafe_counters) { + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using threadsafe instrumentation\n"); + } + else + { + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using non-threadsafe instrumentation\n"); + } + + } unsigned PrevLocSize = 0; unsigned PrevCallerSize = 0; @@ -628,57 +642,63 @@ bool AFLCoverage::runOnModule(Module &M) { /* Update bitmap */ -#if 1 /* Atomic */ -#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 - if (!skip_nozero) { -#endif + if (use_threadsafe_counters) {/* Atomic */ + + #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 + if (!skip_nozero) { + + #endif // register MapPtrIdx in a todo list todo.push_back(MapPtrIdx); - } else { - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, llvm::AtomicOrdering::Monotonic); + } + 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)); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - Value *Incr = IRB.CreateAdd(Counter, One); + Value *Incr = IRB.CreateAdd(Counter, One); -#if LLVM_VERSION_MAJOR < 9 - if (neverZero_counters_str != - NULL) { // with llvm 9 we make this the default as the bug in llvm is - // then fixed -#else - if (!skip_nozero) { + #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 + if (!skip_nozero) { -#endif - /* hexcoder: Realize a 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 - */ + #endif + /* hexcoder: Realize a 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 + */ - ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + ConstantInt *Zero = ConstantInt::get(Int8Ty, 0); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - } + } - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); -#endif /* 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) */ @@ -735,99 +755,104 @@ bool AFLCoverage::runOnModule(Module &M) { } -#if 1 /*Atomic NeverZero */ - // handle the todo list - for (auto val : todo) { + 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 + * Thanks to + https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ - /* equivalent c code looks like this - * Thanks to https://preshing.com/20150402/you-can-do-any-kind-of-atomic-read-modify-write-operation/ + 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)); - 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)); + */ - */ + Value * MapPtrIdx = val; + Instruction * MapPtrIdxInst = cast(val); + BasicBlock::iterator it0(&(*MapPtrIdxInst)); + ++it0; + IRBuilder<> IRB(&(*it0)); - Value * MapPtrIdx = val; - Instruction * MapPtrIdxInst = cast(val); - BasicBlock::iterator it0(&(*MapPtrIdxInst)); - ++it0; - IRBuilder<> IRB(&(*it0)); + // load the old counter value atomically + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setAlignment(llvm::Align()); + Counter->setAtomic(llvm::AtomicOrdering::Monotonic); + Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - // load the old counter value atomically - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setAlignment(llvm::Align()); - Counter->setAtomic(llvm::AtomicOrdering::Monotonic); - Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + 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 - 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 + BasicBlock::iterator it(*Counter); + it++; // split after load counter + BasicBlock *end_bb = BB->splitBasicBlock(it); + end_bb->setName("injected"); - BasicBlock::iterator it(*Counter); it++; // split after load counter - BasicBlock * end_bb = BB->splitBasicBlock(it); - end_bb->setName("injected"); + // insert the block before the second half of the split + BasicBlock *do_while_bb = + BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); - // insert the block before the second half of the split - BasicBlock * do_while_bb = BasicBlock::Create(C, "injected", end_bb->getParent(), end_bb); + // set terminator of BB from target end_bb to target do_while_bb + auto term = BB->getTerminator(); + BranchInst::Create(do_while_bb, BB); + term->eraseFromParent(); - // set terminator of BB from target end_bb to target do_while_bb - auto term = BB->getTerminator(); - BranchInst::Create(do_while_bb, BB); - term->eraseFromParent(); + // continue to fill instructions into the do_while loop + IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); - // continue to fill instructions into the do_while loop - IRB.SetInsertPoint(do_while_bb, do_while_bb->getFirstInsertionPt()); + PHINode *PN = IRB.CreatePHI(Int8Ty, 2); - PHINode * PN = IRB.CreatePHI(Int8Ty, 2); + // compare with maximum value 0xff + auto *Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); - // compare with maximum value 0xff - auto * Cmp = IRB.CreateICmpEQ(Counter, ConstantInt::get(Int8Ty, -1)); + // increment the counter + Value *Incr = IRB.CreateAdd(Counter, One); - // increment the counter - Value *Incr = IRB.CreateAdd(Counter, One); + // select the counter value or 1 + auto *Select = IRB.CreateSelect(Cmp, One, Incr); - // select the counter value or 1 - auto * Select = IRB.CreateSelect(Cmp, One, Incr); + // try to save back the new counter value + auto *CmpXchg = IRB.CreateAtomicCmpXchg( + MapPtrIdx, PN, Select, llvm::AtomicOrdering::Monotonic, + llvm::AtomicOrdering::Monotonic); + CmpXchg->setAlignment(llvm::Align()); + CmpXchg->setWeak(true); + CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); - // try to save back the new counter value - auto * CmpXchg = IRB.CreateAtomicCmpXchg(MapPtrIdx, PN, Select, - llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Monotonic); - CmpXchg->setAlignment(llvm::Align()); - CmpXchg->setWeak(true); - CmpXchg->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); + // get the result of trying to update the Counter + Value *Success = + IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); + // get the (possibly updated) value of Counter + Value *OldVal = + IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); - // get the result of trying to update the Counter - Value * Success = IRB.CreateExtractValue(CmpXchg, ArrayRef({1})); - // get the (possibly updated) value of Counter - Value * OldVal = IRB.CreateExtractValue(CmpXchg, ArrayRef({0})); + // initially we use Counter + PN->addIncoming(Counter, BB); + // on retry, we use the updated value + PN->addIncoming(OldVal, do_while_bb); - // initially we use Counter - PN->addIncoming(Counter, BB); - // on retry, we use the updated value - PN->addIncoming(OldVal, do_while_bb); + // if the cmpXchg was not successful, retry + IRB.CreateCondBr(Success, end_bb, do_while_bb); + } - // if the cmpXchg was not successful, retry - IRB.CreateCondBr(Success, end_bb, do_while_bb); - - } -#endif + } } diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 06d0a0f8..1152cc4e 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -43,6 +43,36 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { $ECHO "$RED[!] llvm_mode failed" CODE=1 } + AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_THREADSAFE_INST=1 ../afl-clang-fast -o test-instr.ts ../test-instr.c > /dev/null 2>&1 + test -e test-instr.ts && { + $ECHO "$GREEN[+] llvm_mode threadsafe compilation succeeded" + echo 0 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.0 -r -- ./test-instr.ts > /dev/null 2>&1 + AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o test-instr.ts.1 -r -- ./test-instr.ts < /dev/null > /dev/null 2>&1 + test -e test-instr.ts.0 -a -e test-instr.ts.1 && { + diff test-instr.ts.0 test-instr.ts.1 > /dev/null 2>&1 && { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation should be different on different input but is not" + CODE=1 + } || { + $ECHO "$GREEN[+] llvm_mode threadsafe instrumentation present and working correctly" + TUPLES=`echo 0|AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o /dev/null -- ./test-instr.ts 2>&1 | grep Captur | awk '{print$3}'` + test "$TUPLES" -gt 2 -a "$TUPLES" -lt 8 && { + $ECHO "$GREEN[+] llvm_mode run reported $TUPLES threadsafe instrumented locations which is fine" + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation produces weird numbers: $TUPLES" + CODE=1 + } + test "$TUPLES" -lt 3 && SKIP=1 + true + } + } || { + $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed" + CODE=1 + } + rm -f test-instr.ts.0 test-instr.ts.1 + } || { + $ECHO "$RED[!] llvm_mode (threadsafe) failed" + CODE=1 + } ../afl-clang-fast -DTEST_SHARED_OBJECT=1 -z defs -fPIC -shared -o test-instr.so ../test-instr.c > /dev/null 2>&1 test -e test-instr.so && { $ECHO "$GREEN[+] llvm_mode shared object with -z defs compilation succeeded" From eb74a7a8004e8281cda62525bbc1f3bbe7f5d9da Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 30 May 2021 12:43:30 +0200 Subject: [PATCH 8/9] 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(+) 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 From b246de789105750558f3d6f884ba61e54cb98441 Mon Sep 17 00:00:00 2001 From: hexcoder- Date: Sun, 30 May 2021 15:25:10 +0200 Subject: [PATCH 9/9] add support for AFL_LLVM_THREADSAFE_INST to other LLVM passes --- instrumentation/README.neverzero.md | 9 ++-- instrumentation/SanitizerCoverageLTO.so.cc | 46 +++++++++++-------- .../SanitizerCoveragePCGUARD.so.cc | 35 ++++++++------ .../afl-llvm-lto-instrumentation.so.cc | 36 ++++++++------- instrumentation/afl-llvm-pass.so.cc | 15 ++++-- 5 files changed, 83 insertions(+), 58 deletions(-) diff --git a/instrumentation/README.neverzero.md b/instrumentation/README.neverzero.md index 06334eab..9bcae324 100644 --- a/instrumentation/README.neverzero.md +++ b/instrumentation/README.neverzero.md @@ -16,11 +16,12 @@ at a very little cost (one instruction per edge). (The alternative of saturated counters has been tested also and proved to be inferior in terms of path discovery.) -This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is optional if -the llvm version is below 9 - as there is a perfomance bug that is only fixed -in version 9 and onwards. +This is implemented in afl-gcc and afl-gcc-fast, however for llvm_mode this is +optional if multithread safe counters are selected or the llvm version is below +9 - as there are severe performance costs in these cases. -If you want to enable this for llvm versions below 9 then set +If you want to enable this for llvm versions below 9 or thread safe counters +then set ``` export AFL_LLVM_NOT_ZERO=1 diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index cd6b1939..f5af32d2 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -237,7 +237,8 @@ class ModuleSanitizerCoverage { uint32_t inst = 0; uint32_t afl_global_id = 0; uint64_t map_addr = 0; - char * skip_nozero = NULL; + const char * skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; std::vector BlockList; DenseMap valueMap; std::vector dictionary; @@ -438,6 +439,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL) if ((afl_global_id = atoi(ptr)) < 0) @@ -1209,7 +1211,7 @@ void ModuleSanitizerCoverage::instrumentFunction( return; // Should not instrument sanitizer init functions. if (F.getName().startswith("__sanitizer_")) return; // Don't instrument __sanitizer_* callbacks. - // Don't touch available_externally functions, their actual body is elewhere. + // Don't touch available_externally functions, their actual body is elsewhere. if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return; // Don't instrument MSVC CRT configuration helpers. They may run before normal // initialization. @@ -1496,27 +1498,33 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, } /* Update bitmap */ -#if 1 /* Atomic */ - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, - llvm::AtomicOrdering::Monotonic); + if (use_threadsafe_counters) { /* Atomic */ -#else - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); - - Value *Incr = IRB.CreateAdd(Counter, One); - - if (skip_nozero == NULL) { - - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Tyi); - Incr = IRB.CreateAdd(Incr, carry); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); } + else + { - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); -#endif + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + Counter->setMetadata(Mo->getMDKindID("nosanitize"), + MDNode::get(*Ct, None)); + + Value *Incr = IRB.CreateAdd(Counter, One); + + if (skip_nozero == NULL) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Tyi); + Incr = IRB.CreateAdd(Incr, carry); + + } + + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(Mo->getMDKindID("nosanitize"), MDNode::get(*Ct, None)); + + } // done :) inst++; diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index dd2e1459..e1e922be 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -96,7 +96,8 @@ static const char *const SanCovPCsSectionName = "sancov_pcs"; static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; -static char *skip_nozero; +static const char *skip_nozero; +static const char *use_threadsafe_counters; namespace { @@ -396,6 +397,7 @@ bool ModuleSanitizerCoverage::instrumentModule( be_quiet = 1; skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); initInstrumentList(); scanForDangerousFunctions(&M); @@ -1081,27 +1083,32 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, Value * MapPtrIdx = IRB.CreateGEP(MapPtr, CurLoc); -#if 1 /* Atomic */ - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, - llvm::AtomicOrdering::Monotonic); + if (use_threadsafe_counters) { -#else - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + llvm::AtomicOrdering::Monotonic); - /* Update bitmap */ + } + else + { - Value *Incr = IRB.CreateAdd(Counter, One); + LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); + /* Update bitmap */ - if (skip_nozero == NULL) { + Value *Incr = IRB.CreateAdd(Counter, One); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + if (skip_nozero == NULL) { + + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); + + } + + IRB.CreateStore(Incr, MapPtrIdx); } - IRB.CreateStore(Incr, MapPtrIdx); -#endif // done :) // IRB.CreateCall(SanCovTracePCGuard, Offset)->setCannotMerge(); diff --git a/instrumentation/afl-llvm-lto-instrumentation.so.cc b/instrumentation/afl-llvm-lto-instrumentation.so.cc index 5ed13ff0..10cfa579 100644 --- a/instrumentation/afl-llvm-lto-instrumentation.so.cc +++ b/instrumentation/afl-llvm-lto-instrumentation.so.cc @@ -93,7 +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; - char * skip_nozero = NULL; + const char *skip_nozero = NULL; + const char *use_threadsafe_counters = nullptr; }; @@ -131,6 +132,8 @@ bool AFLLTOPass::runOnModule(Module &M) { be_quiet = 1; + use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); + if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) { if ((documentFile = fopen(ptr, "a")) == NULL) @@ -839,29 +842,28 @@ bool AFLLTOPass::runOnModule(Module &M) { /* Update bitmap */ -#if 1 /* Atomic */ - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, - llvm::AtomicOrdering::Monotonic); + 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)); -#else - LoadInst *Counter = IRB.CreateLoad(MapPtrIdx); - Counter->setMetadata(M.getMDKindID("nosanitize"), - MDNode::get(C, None)); + Value *Incr = IRB.CreateAdd(Counter, One); - Value *Incr = IRB.CreateAdd(Counter, One); + if (skip_nozero == NULL) { - if (skip_nozero == NULL) { + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + } + IRB.CreateStore(Incr, MapPtrIdx) + ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); } - IRB.CreateStore(Incr, MapPtrIdx) - ->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None)); -#endif - // done :) inst_blocks++; diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 3b1119fc..fe9e2e40 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -85,8 +85,8 @@ class AFLCoverage : public ModulePass { uint32_t ctx_k = 0; uint32_t map_size = MAP_SIZE; uint32_t function_minimum_size = 1; - char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; - char * use_threadsafe_counters = nullptr; + const char * ctx_str = NULL, *caller_str = NULL, *skip_nozero = NULL; + const char * use_threadsafe_counters = nullptr; }; @@ -188,11 +188,18 @@ bool AFLCoverage::runOnModule(Module &M) { if ((isatty(2) && !getenv("AFL_QUIET")) || !!getenv("AFL_DEBUG")) { if (use_threadsafe_counters) { - SAYF(cCYA "afl-llvm-pass" VERSION cRST " using threadsafe instrumentation\n"); + 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-threadsafe instrumentation\n"); + SAYF(cCYA "afl-llvm-pass" VERSION cRST " using non-thread safe instrumentation\n"); } }