From 4d493452a45655073d1b7b1dfe4ad04772b3c2b8 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 25 Jan 2024 17:00:53 +0100 Subject: tmp --- instrumentation/SanitizerCoverageLTO.so.cc | 55 ++++++++++++++++++++++++++++-- src/afl-cc.c | 10 ++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 68423029..c74069e1 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -247,6 +247,7 @@ class ModuleSanitizerCoverageLTO uint32_t afl_global_id = 0; uint32_t unhandled = 0; uint32_t select_cnt = 0; + uint32_t instrument_ctx = 0; uint64_t map_addr = 0; const char *skip_nozero = NULL; const char *use_threadsafe_counters = nullptr; @@ -261,6 +262,7 @@ class ModuleSanitizerCoverageLTO LLVMContext *Ct = NULL; Module *Mo = NULL; GlobalVariable *AFLMapPtr = NULL; + GlobalVariable *AFLContext = NULL; Value *MapPtrFixed = NULL; std::ofstream dFile; size_t found = 0; @@ -420,11 +422,13 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( setvbuf(stdout, NULL, _IONBF, 0); if (getenv("AFL_DEBUG")) { debug = 1; } if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; } + if (getenv("AFL_LLVM_CALLER")) { instrument_ctx = 1; } if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { SAYF(cCYA "afl-llvm-lto" VERSION cRST - " by Marc \"vanHauser\" Heuse \n"); + "%s by Marc \"vanHauser\" Heuse \n", + instrument_ctx ? " (CTX mode)" : ""); } else @@ -500,6 +504,10 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( } + AFLContext = new GlobalVariable( + M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_prev_ctx", 0, + GlobalVariable::GeneralDynamicTLSModel, 0, false); + Zero = ConstantInt::get(Int8Tyi, 0); One = ConstantInt::get(Int8Tyi, 1); @@ -1284,7 +1292,50 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); bool IsLeafFunc = true; - uint32_t skip_next = 0; + uint32_t skip_next = 0, call_counter = 0; + Value *PrevCtx = NULL; + + MDNode *N = + MDNode::get(F.getContext(), MDString::get(F.getContext(), "nosanitize")); + + for (auto &BB : F) { + + if (/*F.size() > 1 &&*/ instrument_ctx && &BB == &F.getEntryBlock()) { + + // we insert a CTX value in all our callers: + LLVMContext &Context = F.getContext(); + IRBuilder<> Builder(Context); + for (auto *U : F.users()) { + + if (auto *CI = dyn_cast(U)) { + + fprintf(stderr, "Insert %s [%u] -> %s\n", + CI->getParent()->getParent()->getName().str().c_str(), + call_counter, F.getName().str().c_str()); + Builder.SetInsertPoint(CI); + StoreInst *StoreCtx = Builder.CreateStore( + ConstantInt::get(Type::getInt32Ty(Context), call_counter++), + AFLContext); + StoreCtx->setMetadata("nosanitize", N); + + } + + } + + // We read the CTX for this call + BasicBlock::iterator IP = BB.getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + LoadInst *PrevCtxLoad = IRB.CreateLoad( +#if LLVM_VERSION_MAJOR >= 14 + Builder.getInt32Ty(), +#endif + AFLContext); + PrevCtxLoad->setMetadata("nosanitize", N); + PrevCtx = PrevCtxLoad; + + } + + } for (auto &BB : F) { diff --git a/src/afl-cc.c b/src/afl-cc.c index 174b3783..4f6745ed 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1103,12 +1103,18 @@ static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) { } - if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM) + fprintf(stderr, "X %u %u\n", aflcc->compiler_mode, LTO); + + if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM && + !((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) && + aflcc->compiler_mode == LTO)) FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode"); if (aflcc->instrument_opt_mode && aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV && - aflcc->instrument_mode != INSTRUMENT_CLASSIC) + aflcc->instrument_mode != INSTRUMENT_CLASSIC && + !(aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER && + aflcc->compiler_mode == LTO)) FATAL( "CALLER, CTX and NGRAM instrumentation options can only be used with " "the LLVM CLASSIC instrumentation mode."); -- cgit 1.4.1 From b0a912a83881052b3ce476459d8c8edfab59c2f9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 26 Jan 2024 12:15:42 +0100 Subject: working ugly version --- instrumentation/SanitizerCoverageLTO.so.cc | 448 +++++++++++++++++++++-------- 1 file changed, 330 insertions(+), 118 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index c74069e1..54cc1752 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -192,12 +192,14 @@ class ModuleSanitizerCoverageLTO PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); private: - void instrumentFunction(Function &F, DomTreeCallback DTCallback, - PostDomTreeCallback PDTCallback); - void InjectCoverageForIndirectCalls(Function &F, - ArrayRef IndirCalls); - bool InjectCoverage(Function &F, ArrayRef AllBlocks, - bool IsLeafFunc = true); + void instrumentFunction(Function &F, DomTreeCallback DTCallback, + PostDomTreeCallback PDTCallback); + void InjectCoverageForIndirectCalls(Function &F, + ArrayRef IndirCalls); + bool InjectCoverage(Function &F, ArrayRef AllBlocks, + bool IsLeafFunc = true); + bool Fake_InjectCoverage(Function &F, ArrayRef AllBlocks, + bool IsLeafFunc = true); GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements, Function &F, Type *Ty, const char *Section); @@ -248,6 +250,7 @@ class ModuleSanitizerCoverageLTO uint32_t unhandled = 0; uint32_t select_cnt = 0; uint32_t instrument_ctx = 0; + uint32_t extra_ctx_inst = 0; uint64_t map_addr = 0; const char *skip_nozero = NULL; const char *use_threadsafe_counters = nullptr; @@ -259,6 +262,7 @@ class ModuleSanitizerCoverageLTO IntegerType *Int64Tyi = NULL; ConstantInt *Zero = NULL; ConstantInt *One = NULL; + AllocaInst *CTX_add = NULL; LLVMContext *Ct = NULL; Module *Mo = NULL; GlobalVariable *AFLMapPtr = NULL; @@ -1164,9 +1168,10 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( getenv("AFL_USE_TSAN") ? ", TSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); - OKF("Instrumented %u locations (%u selects) without collisions (%llu " - "collisions have been avoided) (%s mode).", - inst, select_cnt, calculateCollisions(inst), modeline); + + OKF("Instrumented %u locations (%u selects) with %u extra map entries " + "for CTX (%s mode).", + inst, select_cnt, extra_ctx_inst, modeline); } @@ -1292,19 +1297,112 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); bool IsLeafFunc = true; - uint32_t skip_next = 0, call_counter = 0; - Value *PrevCtx = NULL; + uint32_t skip_next = 0; + uint32_t call_counter = 0; + uint32_t inst_save = inst; + uint32_t inst_in_this_func = 0; + LLVMContext &Context = F.getContext(); + + MDNode *N = MDNode::get(Context, MDString::get(Context, "nosanitize")); + CTX_add = NULL; + + fprintf(stderr, "Function: %s\n", F.getName().str().c_str()); + + // Fake instrumentation so we can count how much there will be in this + // function + + for (auto &BB : F) { + + for (auto &IN : BB) { + + CallInst *callInst = nullptr; + + if ((callInst = dyn_cast(&IN))) { + + Function *Callee = callInst->getCalledFunction(); + if (!Callee) continue; + if (callInst->getCallingConv() != llvm::CallingConv::C) continue; + StringRef FuncName = Callee->getName(); + + if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; + + ++inst; + + } + + SelectInst *selectInst = nullptr; + + if (!skip_next && (selectInst = dyn_cast(&IN)) && 1 == 0) { + + uint32_t vector_cnt = 0; + Value *condition = selectInst->getCondition(); + auto t = condition->getType(); + + if (t->getTypeID() == llvm::Type::IntegerTyID) { + + skip_next = 1; + inst += 2; + + } else + +#if LLVM_VERSION_MAJOR >= 14 + if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + + FixedVectorType *tt = dyn_cast(t); + if (tt) { + + uint32_t elements = tt->getElementCount().getFixedValue(); + vector_cnt = elements; + inst += vector_cnt * 2; - MDNode *N = - MDNode::get(F.getContext(), MDString::get(F.getContext(), "nosanitize")); + } + + } else + +#endif + { + + continue; + + } + + skip_next = 1; + + } else { + + skip_next = 0; + + } + + } + + if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) + BlocksToInstrument.push_back(&BB); + /* + if (Options.IndirectCalls) + for (auto &Inst : BB) { + + fprintf(stderr, "FUCK TODO\n"); + CallBase *CB = dyn_cast(&Inst); + if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); + /// XXX TODO!!!! set 0 ! + + } + + */ + + } + + Fake_InjectCoverage(F, BlocksToInstrument, IsLeafFunc); + + // CTX init for (auto &BB : F) { - if (/*F.size() > 1 &&*/ instrument_ctx && &BB == &F.getEntryBlock()) { + if (instrument_ctx && &BB == &F.getEntryBlock()) { // we insert a CTX value in all our callers: - LLVMContext &Context = F.getContext(); - IRBuilder<> Builder(Context); + IRBuilder<> Builder(Context); for (auto *U : F.users()) { if (auto *CI = dyn_cast(U)) { @@ -1323,24 +1421,60 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } // We read the CTX for this call + Value *CTX_offset; BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); LoadInst *PrevCtxLoad = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - Builder.getInt32Ty(), + IRB.getInt32Ty(), #endif AFLContext); + PrevCtxLoad->setMetadata("nosanitize", N); - PrevCtx = PrevCtxLoad; + + if (inst == inst_save || call_counter < 2) { + + fprintf(stderr, "%s: ZERO!\n", F.getName().str().c_str()); + CTX_offset = Zero; + + } else { + + fprintf(stderr, "%s: %u * %u\n", F.getName().str().c_str(), + inst - inst_save, call_counter); + CTX_offset = IRB.CreateMul( + ConstantInt::get(Type::getInt32Ty(Context), inst - inst_save), + PrevCtxLoad, "CTXmul", false, true); + + } + + CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); + auto nosan = IRB.CreateStore(CTX_offset, CTX_add); + nosan->setMetadata("nosanitize", N); } } + inst_in_this_func = inst - inst_save; + inst = inst_save; + + // Now the real instrumentation + + IsLeafFunc = true; + skip_next = 0; + for (auto &BB : F) { + // fprintf(stderr, "BB: %s\n", BB.getName().str().c_str()); + for (auto &IN : BB) { + /* + std::string Str; + llvm::raw_string_ostream RSO(Str); + IN.print(RSO); + errs() << RSO.str() << "\n"; + */ CallInst *callInst = nullptr; if ((callInst = dyn_cast(&IN))) { @@ -1363,8 +1497,16 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; - Value *val = ConstantInt::get(Int32Ty, ++afl_global_id); - callInst->setOperand(1, val); + IRBuilder<> Builder(Context); + Value *val = ConstantInt::get(Int32Ty, ++afl_global_id); + LoadInst *CTX_load = Builder.CreateLoad( +#if LLVM_VERSION_MAJOR >= 14 + Builder.getInt32Ty(), +#endif + CTX_add); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); + Value *val2 = Builder.CreateAdd(val, CTX_load); + callInst->setOperand(1, val2); ++inst; } @@ -1377,158 +1519,193 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( IN.print(os); fprintf(stderr, "X(%u): %s\n", skip_next, os.str().c_str()); */ - if (!skip_next && (selectInst = dyn_cast(&IN))) { + if ((selectInst = dyn_cast(&IN))) { - uint32_t vector_cnt = 0; - Value *condition = selectInst->getCondition(); - Value *result; - auto t = condition->getType(); - IRBuilder<> IRB(selectInst->getNextNode()); - - ++select_cnt; - - if (t->getTypeID() == llvm::Type::IntegerTyID) { - - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - result = IRB.CreateSelect(condition, val1, val2); - skip_next = 1; - inst += 2; + if (!skip_next) { - } else + uint32_t vector_cnt = 0; + Value *condition = selectInst->getCondition(); + Value *result; + auto t = condition->getType(); + IRBuilder<> IRB(selectInst->getNextNode()); + // fprintf(stderr, "ADDING!!!\n"); + LoadInst *CTX_load = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + IRB.getInt32Ty(), +#endif + CTX_add); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); - FixedVectorType *tt = dyn_cast(t); - if (tt) { + ++select_cnt; - uint32_t elements = tt->getElementCount().getFixedValue(); - vector_cnt = elements; - inst += vector_cnt * 2; - if (elements) { + if (t->getTypeID() == llvm::Type::IntegerTyID) { - FixedVectorType *GuardPtr1 = - FixedVectorType::get(Int32Ty, elements); - FixedVectorType *GuardPtr2 = - FixedVectorType::get(Int32Ty, elements); - Value *x, *y; + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val11 = IRB.CreateAdd(val1, CTX_load); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val22 = IRB.CreateAdd(val2, CTX_load); + result = IRB.CreateSelect(condition, val11, val22); + skip_next = 1; + inst += 2; - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); - y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); + } else + +#if LLVM_VERSION_MAJOR >= 14 + if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + + FixedVectorType *tt = dyn_cast(t); + if (tt) { + + uint32_t elements = tt->getElementCount().getFixedValue(); + vector_cnt = elements; + inst += vector_cnt * 2; + if (elements) { + + FixedVectorType *GuardPtr1 = + FixedVectorType::get(Int32Ty, elements); + FixedVectorType *GuardPtr2 = + FixedVectorType::get(Int32Ty, elements); + Value *x, *y; + + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val11 = IRB.CreateAdd(val1, CTX_add); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val22 = IRB.CreateAdd(val2, CTX_add); + x = IRB.CreateInsertElement(GuardPtr1, val11, (uint64_t)0); + y = IRB.CreateInsertElement(GuardPtr2, val22, (uint64_t)0); + + for (uint64_t i = 1; i < elements; i++) { + + val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + val11 = IRB.CreateAdd(val1, CTX_add); + val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + val11 = IRB.CreateAdd(val1, CTX_add); + x = IRB.CreateInsertElement(GuardPtr1, val11, i); + y = IRB.CreateInsertElement(GuardPtr2, val22, i); - for (uint64_t i = 1; i < elements; i++) { + } - val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - x = IRB.CreateInsertElement(GuardPtr1, val1, i); - y = IRB.CreateInsertElement(GuardPtr2, val2, i); + result = IRB.CreateSelect(condition, x, y); + skip_next = 1; } - result = IRB.CreateSelect(condition, x, y); - skip_next = 1; - } - } - - } else + } else #endif - { + { - unhandled++; - continue; + unhandled++; + continue; - } + } - uint32_t vector_cur = 0; - /* Load SHM pointer */ - LoadInst *MapPtr = - IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); + uint32_t vector_cur = 0; + /* Load SHM pointer */ + LoadInst *MapPtr = + IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); - while (1) { + while (1) { - /* Get CurLoc */ - Value *MapPtrIdx = nullptr; + /* Get CurLoc */ + Value *MapPtrIdx = nullptr; - /* Load counter for CurLoc */ - if (!vector_cnt) { + /* Load counter for CurLoc */ + if (!vector_cnt) { - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); - } else { + } else { - auto element = IRB.CreateExtractElement(result, vector_cur++); - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); + auto element = IRB.CreateExtractElement(result, vector_cur++); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); - } + } - if (use_threadsafe_counters) { + if (use_threadsafe_counters) { - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, + One, #if LLVM_VERSION_MAJOR >= 13 - llvm::MaybeAlign(1), + llvm::MaybeAlign(1), #endif - llvm::AtomicOrdering::Monotonic); + llvm::AtomicOrdering::Monotonic); - } else { + } else { - LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); + LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); - /* Update bitmap */ + /* Update bitmap */ - 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); + + } + + auto nosan = IRB.CreateStore(Incr, MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); } - auto nosan = IRB.CreateStore(Incr, MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); + if (!vector_cnt || vector_cnt == vector_cur) { break; } } - if (!vector_cnt || vector_cnt == vector_cur) { break; } + skip_next = 1; - } + } else { - skip_next = 1; + skip_next = 0; - } else { - - skip_next = 0; + } } } - if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) - BlocksToInstrument.push_back(&BB); - for (auto &Inst : BB) { + // if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) + // BlocksToInstrument.push_back(&BB); - if (Options.IndirectCalls) { + } - CallBase *CB = dyn_cast(&Inst); - if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); + InjectCoverage(F, BlocksToInstrument, IsLeafFunc); + // InjectCoverageForIndirectCalls(F, IndirCalls); - } + if (inst_in_this_func && call_counter > 1) { - } + extra_ctx_inst += inst_in_this_func * (call_counter - 1); + afl_global_id += inst_in_this_func * (call_counter - 1); } - InjectCoverage(F, BlocksToInstrument, IsLeafFunc); - InjectCoverageForIndirectCalls(F, IndirCalls); + /* + fprintf(stderr, "FUNCTION: %s\n", F.getName().str().c_str()); + int n = 0; + for (auto &BB : F) { + + fprintf(stderr, "BB %d\n", n++); + for (auto &IN : BB) { + + std::string Str; + llvm::raw_string_ostream RSO(Str); + IN.print(RSO); + errs() << RSO.str() << "\n"; + + } + + } + + */ } @@ -1654,6 +1831,36 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage( } +// Fake InjectCoverage to count the instrumentations +bool ModuleSanitizerCoverageLTO::Fake_InjectCoverage( + Function &F, ArrayRef AllBlocks, bool IsLeafFunc) { + + if (AllBlocks.empty()) return false; + + for (size_t i = 0, N = AllBlocks.size(); i < N; i++) { + + // AFL++ START + if (BlockList.size()) { + + int skip = 0; + for (uint32_t k = 0; k < BlockList.size(); k++) { + + if (AllBlocks[i] == BlockList[k]) { skip = 1; } + + } + + if (skip) continue; + + } + + inst++; // InjectCoverageAtBlock() + + } + + return true; + +} + // On every indirect call we call a run-time function // __sanitizer_cov_indir_call* with two parameters: // - callee address, @@ -1725,6 +1932,13 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, /* Set the ID of the inserted basic block */ ConstantInt *CurLoc = ConstantInt::get(Int32Tyi, afl_global_id); + LoadInst *CTX_load = IRB.CreateLoad( +#if LLVM_VERSION_MAJOR >= 14 + IRB.getInt32Ty(), +#endif + CTX_add); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); + Value *offset = IRB.CreateAdd(CurLoc, CTX_load); /* Load SHM pointer */ @@ -1732,13 +1946,13 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, if (map_addr) { - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, CurLoc); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, offset); } else { LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, CurLoc); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, offset); } @@ -1777,8 +1991,6 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, // AFL++ END /* - XXXXXXXXXXXXXXXXXXX - auto GuardPtr = IRB.CreateIntToPtr( IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), ConstantInt::get(IntptrTy, Idx * 4)), -- cgit 1.4.1 From 44a7696169f52f6ef8b5c9a5a6de1167000e2138 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 26 Jan 2024 15:27:20 +0100 Subject: fixes --- instrumentation/SanitizerCoverageLTO.so.cc | 42 +++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 54cc1752..b280e947 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1453,6 +1453,24 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } + // we have to set __afl_ctx 0 for all indirect calls + for (auto &IN : BB) { + + if (auto *Call = dyn_cast(&IN)) { + + if (Call->isIndirectCall()) { + + IRBuilder<> Builder(IN.getContext()); + Builder.SetInsertPoint(IN.getParent(), IN.getIterator()); + StoreInst *StoreCtx = Builder.CreateStore(Zero, AFLContext); + StoreCtx->setMetadata("nosanitize", N); + + } + + } + + } + } inst_in_this_func = inst - inst_save; @@ -1569,18 +1587,18 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( Value *x, *y; Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val11 = IRB.CreateAdd(val1, CTX_add); + Value *val11 = IRB.CreateAdd(val1, CTX_load); Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val22 = IRB.CreateAdd(val2, CTX_add); + Value *val22 = IRB.CreateAdd(val2, CTX_load); x = IRB.CreateInsertElement(GuardPtr1, val11, (uint64_t)0); y = IRB.CreateInsertElement(GuardPtr2, val22, (uint64_t)0); for (uint64_t i = 1; i < elements; i++) { val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - val11 = IRB.CreateAdd(val1, CTX_add); + val11 = IRB.CreateAdd(val1, CTX_load); val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - val11 = IRB.CreateAdd(val1, CTX_add); + val11 = IRB.CreateAdd(val1, CTX_load); x = IRB.CreateInsertElement(GuardPtr1, val11, i); y = IRB.CreateInsertElement(GuardPtr2, val22, i); @@ -1628,12 +1646,13 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (use_threadsafe_counters) { - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, - One, + auto nosan = IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, + MapPtrIdx, One, #if LLVM_VERSION_MAJOR >= 13 - llvm::MaybeAlign(1), + llvm::MaybeAlign(1), #endif - llvm::AtomicOrdering::Monotonic); + llvm::AtomicOrdering::Monotonic); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); } else { @@ -1684,14 +1703,13 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (inst_in_this_func && call_counter > 1) { extra_ctx_inst += inst_in_this_func * (call_counter - 1); - afl_global_id += inst_in_this_func * (call_counter - 1); + afl_global_id += extra_ctx_inst; } /* - fprintf(stderr, "FUNCTION: %s\n", F.getName().str().c_str()); - int n = 0; - for (auto &BB : F) { + fprintf(stderr, "FUNCTION: %s [%u]\n", F.getName().str().c_str(), + extra_ctx_inst); int n = 0; for (auto &BB : F) { fprintf(stderr, "BB %d\n", n++); for (auto &IN : BB) { -- cgit 1.4.1 From d668010bedf5373e25ea12c24dbb477f54da91ba Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 26 Jan 2024 16:44:31 +0100 Subject: fixes --- instrumentation/SanitizerCoverageLTO.so.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index b280e947..a3074ae2 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -249,7 +249,7 @@ class ModuleSanitizerCoverageLTO uint32_t afl_global_id = 0; uint32_t unhandled = 0; uint32_t select_cnt = 0; - uint32_t instrument_ctx = 0; + uint32_t instrument_ctx = 1; uint32_t extra_ctx_inst = 0; uint64_t map_addr = 0; const char *skip_nozero = NULL; @@ -1481,6 +1481,18 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( IsLeafFunc = true; skip_next = 0; + if (CTX_add == NULL) { + + auto BB = &F.getEntryBlock(); + fprintf(stderr, "NULL %s %p\n", F.getName().str().c_str(), BB); + if (!BB) { exit(-1); } + BasicBlock::iterator IP = BB->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); + auto nosan = IRB.CreateStore(Zero, CTX_add); + nosan->setMetadata("nosanitize", N); + } + for (auto &BB : F) { // fprintf(stderr, "BB: %s\n", BB.getName().str().c_str()); -- cgit 1.4.1 From ceb7e44e6fb614c3efd684b6a1ee71fa89a6fe24 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Jan 2024 08:28:47 +0100 Subject: fixes --- instrumentation/SanitizerCoverageLTO.so.cc | 56 ++++++++++++++++-------------- 1 file changed, 30 insertions(+), 26 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index a3074ae2..3a02cf08 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1299,7 +1299,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( bool IsLeafFunc = true; uint32_t skip_next = 0; uint32_t call_counter = 0; - uint32_t inst_save = inst; + uint32_t inst_save = inst, save_global = afl_global_id; uint32_t inst_in_this_func = 0; LLVMContext &Context = F.getContext(); @@ -1332,15 +1332,13 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( SelectInst *selectInst = nullptr; - if (!skip_next && (selectInst = dyn_cast(&IN)) && 1 == 0) { + if ((selectInst = dyn_cast(&IN))) { - uint32_t vector_cnt = 0; - Value *condition = selectInst->getCondition(); - auto t = condition->getType(); + Value *condition = selectInst->getCondition(); + auto t = condition->getType(); if (t->getTypeID() == llvm::Type::IntegerTyID) { - skip_next = 1; inst += 2; } else @@ -1352,8 +1350,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (tt) { uint32_t elements = tt->getElementCount().getFixedValue(); - vector_cnt = elements; - inst += vector_cnt * 2; + inst += elements * 2; } @@ -1366,12 +1363,6 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } - skip_next = 1; - - } else { - - skip_next = 0; - } } @@ -1478,19 +1469,22 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( // Now the real instrumentation - IsLeafFunc = true; - skip_next = 0; - if (CTX_add == NULL) { - auto BB = &F.getEntryBlock(); + auto BB = &F.getEntryBlock(); + if (!BB) { + fprintf(stderr, "NULL %s %p\n", F.getName().str().c_str(), BB); - if (!BB) { exit(-1); } - BasicBlock::iterator IP = BB->getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); - auto nosan = IRB.CreateStore(Zero, CTX_add); - nosan->setMetadata("nosanitize", N); + exit(-1); + + } + + BasicBlock::iterator IP = BB->getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); + auto nosan = IRB.CreateStore(Zero, CTX_add); + nosan->setMetadata("nosanitize", N); + } for (auto &BB : F) { @@ -1590,6 +1584,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( uint32_t elements = tt->getElementCount().getFixedValue(); vector_cnt = elements; inst += vector_cnt * 2; + if (elements) { FixedVectorType *GuardPtr1 = @@ -1714,6 +1709,15 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (inst_in_this_func && call_counter > 1) { + if (inst_in_this_func != afl_global_id - save_global) { + + fprintf( + stderr, + "BUG! inst_in_this_func %u != afl_global_id %u - save_global %u\n", + inst_in_this_func, afl_global_id, save_global); + + } + extra_ctx_inst += inst_in_this_func * (call_counter - 1); afl_global_id += extra_ctx_inst; @@ -1883,7 +1887,7 @@ bool ModuleSanitizerCoverageLTO::Fake_InjectCoverage( } - inst++; // InjectCoverageAtBlock() + ++inst; // InjectCoverageAtBlock() } @@ -2017,7 +2021,7 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, // done :) - inst++; + ++inst; // AFL++ END /* -- cgit 1.4.1 From e6eee685ceedf92d5ce6dd1c32412e286b4f6104 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 27 Jan 2024 15:13:27 +0100 Subject: fix --- instrumentation/SanitizerCoverageLTO.so.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 3a02cf08..469df42e 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -261,6 +261,7 @@ class ModuleSanitizerCoverageLTO IntegerType *Int32Tyi = NULL; IntegerType *Int64Tyi = NULL; ConstantInt *Zero = NULL; + ConstantInt *Zero32 = NULL; ConstantInt *One = NULL; AllocaInst *CTX_add = NULL; LLVMContext *Ct = NULL; @@ -513,6 +514,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( GlobalVariable::GeneralDynamicTLSModel, 0, false); Zero = ConstantInt::get(Int8Tyi, 0); + Zero32 = ConstantInt::get(Int32Tyi, 0); One = ConstantInt::get(Int8Tyi, 1); initInstrumentList(); @@ -1426,7 +1428,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (inst == inst_save || call_counter < 2) { fprintf(stderr, "%s: ZERO!\n", F.getName().str().c_str()); - CTX_offset = Zero; + CTX_offset = Zero32; } else { @@ -1453,7 +1455,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( IRBuilder<> Builder(IN.getContext()); Builder.SetInsertPoint(IN.getParent(), IN.getIterator()); - StoreInst *StoreCtx = Builder.CreateStore(Zero, AFLContext); + StoreInst *StoreCtx = Builder.CreateStore(Zero32, AFLContext); StoreCtx->setMetadata("nosanitize", N); } @@ -1474,7 +1476,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( auto BB = &F.getEntryBlock(); if (!BB) { - fprintf(stderr, "NULL %s %p\n", F.getName().str().c_str(), BB); + fprintf(stderr, "NULL entry %s %p\n", F.getName().str().c_str(), BB); exit(-1); } @@ -1482,7 +1484,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( BasicBlock::iterator IP = BB->getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); - auto nosan = IRB.CreateStore(Zero, CTX_add); + auto nosan = IRB.CreateStore(Zero32, CTX_add); nosan->setMetadata("nosanitize", N); } -- cgit 1.4.1 From 79080355ac1be8f4edc9818daf5530691aad7f3c Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 1 Feb 2024 17:39:23 +0100 Subject: better CTX instrumentation --- instrumentation/SanitizerCoverageLTO.so.cc | 683 +++++++++++++++++------------ 1 file changed, 413 insertions(+), 270 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 469df42e..f6d60099 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -194,8 +194,9 @@ class ModuleSanitizerCoverageLTO private: void instrumentFunction(Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback); - void InjectCoverageForIndirectCalls(Function &F, - ArrayRef IndirCalls); + /* void InjectCoverageForIndirectCalls(Function &F, + ArrayRef + IndirCalls);*/ bool InjectCoverage(Function &F, ArrayRef AllBlocks, bool IsLeafFunc = true); bool Fake_InjectCoverage(Function &F, ArrayRef AllBlocks, @@ -263,12 +264,12 @@ class ModuleSanitizerCoverageLTO ConstantInt *Zero = NULL; ConstantInt *Zero32 = NULL; ConstantInt *One = NULL; - AllocaInst *CTX_add = NULL; LLVMContext *Ct = NULL; Module *Mo = NULL; - GlobalVariable *AFLMapPtr = NULL; GlobalVariable *AFLContext = NULL; + GlobalVariable *AFLMapPtr = NULL; Value *MapPtrFixed = NULL; + AllocaInst *CTX_add = NULL; std::ofstream dFile; size_t found = 0; // AFL++ END @@ -427,7 +428,11 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( setvbuf(stdout, NULL, _IONBF, 0); if (getenv("AFL_DEBUG")) { debug = 1; } if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; } - if (getenv("AFL_LLVM_CALLER")) { instrument_ctx = 1; } + if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_CTX")) { + + instrument_ctx = 1; + + } if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { @@ -435,10 +440,12 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( "%s by Marc \"vanHauser\" Heuse \n", instrument_ctx ? " (CTX mode)" : ""); - } else + } else { be_quiet = 1; + } + skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); @@ -611,12 +618,12 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( } dictionary.push_back(std::string((char *)&val, len)); - found++; + ++found; if (val2) { dictionary.push_back(std::string((char *)&val2, len)); - found++; + ++found; } @@ -943,7 +950,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( '\0') { thestring.append("\0", 1); // add null byte - optLen++; + ++optLen; } @@ -1094,7 +1101,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( for (auto token : dictionary) { memlen += token.length(); - count++; + ++count; } @@ -1115,7 +1122,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( ptrhld.get()[offset++] = (uint8_t)token.length(); memcpy(ptrhld.get() + offset, token.c_str(), token.length()); offset += token.length(); - count++; + ++count; } @@ -1162,7 +1169,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( WARNF("No instrumentation targets found."); else { - char modeline[100]; + char modeline[128]; snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s", getenv("AFL_HARDEN") ? "hardened" : "non-hardened", getenv("AFL_USE_ASAN") ? ", ASAN" : "", @@ -1170,10 +1177,16 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( getenv("AFL_USE_TSAN") ? ", TSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); + char buf[64] = {}; + if (instrument_ctx) { - OKF("Instrumented %u locations (%u selects) with %u extra map entries " - "for CTX (%s mode).", - inst, select_cnt, extra_ctx_inst, modeline); + snprintf(buf, sizeof(buf), " with %u extra map entries for CTX", + extra_ctx_inst); + + } + + OKF("Instrumented %u locations (%u selects)%s (%s mode).", inst, + select_cnt, buf, modeline); } @@ -1254,6 +1267,52 @@ static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, } +/// return the number of calls to this function +u32 countCallers(Function *F) { + + u32 callers = 0; + + if (!F) { return 0; } + + for (auto *U : F->users()) { + + if (auto *CI = dyn_cast(U)) { ++callers; } + + } + + return callers; + +} + +/// return the calling function of a function - only if there is a single caller +Function *returnOnlyCaller(Function *F) { + + Function *caller = NULL; + + if (!F) { return NULL; } + + for (auto *U : F->users()) { + + if (auto *CI = dyn_cast(U)) { + + if (caller == NULL) { + + caller = CI->getParent()->getParent(); + + } else { + + return NULL; + + } + + } + + } + + return caller; + +} + void ModuleSanitizerCoverageLTO::instrumentFunction( Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { @@ -1287,6 +1346,37 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( // AFL++ START if (!F.size()) return; + + LLVMContext &Context = F.getContext(); + MDNode *N = MDNode::get(Context, MDString::get(Context, "nosanitize")); + + if (instrument_ctx) { + + // we have to set __afl_ctx 0 for all indirect calls in all functions, even + // those not to be instrumented. + for (auto &BB : F) { + + for (auto &IN : BB) { + + if (auto *Call = dyn_cast(&IN)) { + + if (Call->isIndirectCall()) { + + IRBuilder<> Builder(IN.getContext()); + Builder.SetInsertPoint(IN.getParent(), IN.getIterator()); + StoreInst *StoreCtx = Builder.CreateStore(Zero32, AFLContext); + StoreCtx->setMetadata("nosanitize", N); + + } + + } + + } + + } + + } + if (!isInInstrumentList(&F, FMNAME)) return; // AFL++ END @@ -1300,207 +1390,238 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( const PostDominatorTree *PDT = PDTCallback(F); bool IsLeafFunc = true; uint32_t skip_next = 0; - uint32_t call_counter = 0; + uint32_t call_counter = 0, call_depth = 0; uint32_t inst_save = inst, save_global = afl_global_id; uint32_t inst_in_this_func = 0; - LLVMContext &Context = F.getContext(); + Function *caller = NULL; - MDNode *N = MDNode::get(Context, MDString::get(Context, "nosanitize")); CTX_add = NULL; - fprintf(stderr, "Function: %s\n", F.getName().str().c_str()); + if (debug) fprintf(stderr, "Function: %s\n", F.getName().str().c_str()); - // Fake instrumentation so we can count how much there will be in this - // function + if (instrument_ctx) { - for (auto &BB : F) { + caller = &F; + call_counter = countCallers(caller); + Function *callee = caller; - for (auto &IN : BB) { + if (call_counter == 1) { - CallInst *callInst = nullptr; + ++call_depth; - if ((callInst = dyn_cast(&IN))) { + while (((caller = returnOnlyCaller(callee)) || 1 == 1) && + (call_counter = countCallers(callee)) == 1) { - Function *Callee = callInst->getCalledFunction(); - if (!Callee) continue; - if (callInst->getCallingConv() != llvm::CallingConv::C) continue; - StringRef FuncName = Callee->getName(); + if (debug && caller && callee) + fprintf(stderr, "DEBUG: another depth: %s <- %s [%u]\n", + callee->getName().str().c_str(), + caller->getName().str().c_str(), call_depth); + ++call_depth; + callee = caller; - if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; + } - ++inst; + if (!caller && callee) { + + caller = callee; + if (debug) + fprintf(stderr, "DEBUG: depth found: %s <- %s [count=%u, depth=%u]\n", + caller->getName().str().c_str(), F.getName().str().c_str(), + call_counter, call_depth); } - SelectInst *selectInst = nullptr; + } - if ((selectInst = dyn_cast(&IN))) { + if (debug && call_counter < 2) { - Value *condition = selectInst->getCondition(); - auto t = condition->getType(); + fprintf(stderr, "Function %s only %u (%s)\n", F.getName().str().c_str(), + call_counter, caller->getName().str().c_str()); - if (t->getTypeID() == llvm::Type::IntegerTyID) { + } - inst += 2; + if (call_counter == 1) { - } else + call_counter = 0; + caller = NULL; -#if LLVM_VERSION_MAJOR >= 14 - if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + } - FixedVectorType *tt = dyn_cast(t); - if (tt) { + if (debug) { - uint32_t elements = tt->getElementCount().getFixedValue(); - inst += elements * 2; + fprintf(stderr, "DEBUG: result: Function=%s callers=%u depth=%u\n", + F.getName().str().c_str(), call_counter, call_depth); - } + } - } else + if (call_counter > 1) { -#endif - { + // Fake instrumentation so we can count how many instrumentations there + // will be in this function + for (auto &BB : F) { - continue; + for (auto &IN : BB) { - } + CallInst *callInst = nullptr; - } + if ((callInst = dyn_cast(&IN))) { - } + Function *Callee = callInst->getCalledFunction(); + if (!Callee) continue; + if (callInst->getCallingConv() != llvm::CallingConv::C) continue; + StringRef FuncName = Callee->getName(); - if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) - BlocksToInstrument.push_back(&BB); - /* - if (Options.IndirectCalls) - for (auto &Inst : BB) { + if (FuncName.compare(StringRef("__afl_coverage_interesting"))) + continue; - fprintf(stderr, "FUCK TODO\n"); - CallBase *CB = dyn_cast(&Inst); - if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); - /// XXX TODO!!!! set 0 ! + ++inst; } - */ + SelectInst *selectInst = nullptr; - } + if ((selectInst = dyn_cast(&IN))) { - Fake_InjectCoverage(F, BlocksToInstrument, IsLeafFunc); + Value *condition = selectInst->getCondition(); + auto t = condition->getType(); - // CTX init + if (t->getTypeID() == llvm::Type::IntegerTyID) { - for (auto &BB : F) { + inst += 2; - if (instrument_ctx && &BB == &F.getEntryBlock()) { + } else - // we insert a CTX value in all our callers: - IRBuilder<> Builder(Context); - for (auto *U : F.users()) { +#if LLVM_VERSION_MAJOR >= 14 + if (t->getTypeID() == llvm::Type::FixedVectorTyID) { - if (auto *CI = dyn_cast(U)) { + FixedVectorType *tt = dyn_cast(t); + if (tt) { - fprintf(stderr, "Insert %s [%u] -> %s\n", - CI->getParent()->getParent()->getName().str().c_str(), - call_counter, F.getName().str().c_str()); - Builder.SetInsertPoint(CI); - StoreInst *StoreCtx = Builder.CreateStore( - ConstantInt::get(Type::getInt32Ty(Context), call_counter++), - AFLContext); - StoreCtx->setMetadata("nosanitize", N); + uint32_t elements = tt->getElementCount().getFixedValue(); + inst += elements * 2; - } + } - } + } else - // We read the CTX for this call - Value *CTX_offset; - BasicBlock::iterator IP = BB.getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - LoadInst *PrevCtxLoad = IRB.CreateLoad( -#if LLVM_VERSION_MAJOR >= 14 - IRB.getInt32Ty(), #endif - AFLContext); + { - PrevCtxLoad->setMetadata("nosanitize", N); + continue; - if (inst == inst_save || call_counter < 2) { + } - fprintf(stderr, "%s: ZERO!\n", F.getName().str().c_str()); - CTX_offset = Zero32; + } - } else { + } - fprintf(stderr, "%s: %u * %u\n", F.getName().str().c_str(), - inst - inst_save, call_counter); - CTX_offset = IRB.CreateMul( - ConstantInt::get(Type::getInt32Ty(Context), inst - inst_save), - PrevCtxLoad, "CTXmul", false, true); + if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) + BlocksToInstrument.push_back(&BB); } - CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); - auto nosan = IRB.CreateStore(CTX_offset, CTX_add); - nosan->setMetadata("nosanitize", N); + Fake_InjectCoverage(F, BlocksToInstrument, IsLeafFunc); - } + if (debug) + fprintf(stderr, "DEBUG: CTX: %u instrumentations\n", inst - inst_save); - // we have to set __afl_ctx 0 for all indirect calls - for (auto &IN : BB) { + // we only instrument functions that have more than one instrumented block + if (inst > inst_save + 1) { - if (auto *Call = dyn_cast(&IN)) { + inst_in_this_func = inst - inst_save; + bool done = false; - if (Call->isIndirectCall()) { + // in rare occasions there can be multiple entry points per function + for (auto &BB : F) { - IRBuilder<> Builder(IN.getContext()); - Builder.SetInsertPoint(IN.getParent(), IN.getIterator()); - StoreInst *StoreCtx = Builder.CreateStore(Zero32, AFLContext); - StoreCtx->setMetadata("nosanitize", N); + if (&BB == &F.getEntryBlock() && done == false) { - } + // we insert a CTX value in all our callers: + IRBuilder<> Builder(Context); + CallInst *CI = NULL; + Function *F2 = NULL; + uint32_t instrumented_calls = 0; - } + for (auto *U : caller->users()) { - } + if ((CI = dyn_cast(U))) { - } + F2 = CI->getParent()->getParent(); + if (debug) + fprintf(stderr, + "DEBUG: CTX call insert %s [%u/%u] -> %s/%s\n", + F2->getName().str().c_str(), instrumented_calls + 1, + call_counter, caller->getName().str().c_str(), + F.getName().str().c_str()); + + Builder.SetInsertPoint(CI); + StoreInst *StoreCtx = Builder.CreateStore( + ConstantInt::get(Type::getInt32Ty(Context), + instrumented_calls++), + AFLContext); + StoreCtx->setMetadata("nosanitize", N); - inst_in_this_func = inst - inst_save; - inst = inst_save; + } - // Now the real instrumentation + } - if (CTX_add == NULL) { + if (instrumented_calls != call_counter) { - auto BB = &F.getEntryBlock(); - if (!BB) { + fprintf(stderr, "BUG! %s/%s <=> %u vs %u\n", + caller->getName().str().c_str(), + F.getName().str().c_str(), instrumented_calls, + call_counter); + exit(-1); - fprintf(stderr, "NULL entry %s %p\n", F.getName().str().c_str(), BB); - exit(-1); + } - } + done = true; - BasicBlock::iterator IP = BB->getFirstInsertionPt(); - IRBuilder<> IRB(&(*IP)); - CTX_add = IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); - auto nosan = IRB.CreateStore(Zero32, CTX_add); - nosan->setMetadata("nosanitize", N); + } + + // in all entrypoints we have to load the CTX value + if (&BB == &F.getEntryBlock()) { + + Value *CTX_offset; + BasicBlock::iterator IP = BB.getFirstInsertionPt(); + IRBuilder<> IRB(&(*IP)); + LoadInst *PrevCtxLoad = IRB.CreateLoad( +#if LLVM_VERSION_MAJOR >= 14 + IRB.getInt32Ty(), +#endif + AFLContext); + PrevCtxLoad->setMetadata("nosanitize", N); + + CTX_offset = IRB.CreateMul( + ConstantInt::get(Type::getInt32Ty(Context), inst_in_this_func), + PrevCtxLoad, "CTXmul", false, true); + + CTX_add = + IRB.CreateAlloca(Type::getInt32Ty(Context), nullptr, "CTX_add"); + auto nosan = IRB.CreateStore(CTX_offset, CTX_add); + nosan->setMetadata("nosanitize", N); + + if (debug) + fprintf( + stderr, "DEBUG: extra CTX instrumentations for %s: %u * %u\n", + F.getName().str().c_str(), inst - inst_save, call_counter); + + } + + } + + inst = inst_save; + + } + + } } for (auto &BB : F) { - // fprintf(stderr, "BB: %s\n", BB.getName().str().c_str()); - for (auto &IN : BB) { - /* - std::string Str; - llvm::raw_string_ostream RSO(Str); - IN.print(RSO); - errs() << RSO.str() << "\n"; - */ CallInst *callInst = nullptr; if ((callInst = dyn_cast(&IN))) { @@ -1523,16 +1644,21 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue; - IRBuilder<> Builder(Context); - Value *val = ConstantInt::get(Int32Ty, ++afl_global_id); - LoadInst *CTX_load = Builder.CreateLoad( + Value *val = ConstantInt::get(Int32Ty, ++afl_global_id); + if (CTX_add) { + + IRBuilder<> Builder(Context); + LoadInst *CTX_load = Builder.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - Builder.getInt32Ty(), + Builder.getInt32Ty(), #endif - CTX_add); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); - Value *val2 = Builder.CreateAdd(val, CTX_load); - callInst->setOperand(1, val2); + CTX_add); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); + val = Builder.CreateAdd(val, CTX_load); + + } + + callInst->setOperand(1, val); ++inst; } @@ -1545,164 +1671,191 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( IN.print(os); fprintf(stderr, "X(%u): %s\n", skip_next, os.str().c_str()); */ - if ((selectInst = dyn_cast(&IN))) { + if (!skip_next && (selectInst = dyn_cast(&IN))) { + + uint32_t vector_cnt = 0; + Value *condition = selectInst->getCondition(); + Value *result; + auto t = condition->getType(); + IRBuilder<> IRB(selectInst->getNextNode()); + + ++select_cnt; - if (!skip_next) { + if (t->getTypeID() == llvm::Type::IntegerTyID) { - uint32_t vector_cnt = 0; - Value *condition = selectInst->getCondition(); - Value *result; - auto t = condition->getType(); - IRBuilder<> IRB(selectInst->getNextNode()); + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + if (CTX_add) { - // fprintf(stderr, "ADDING!!!\n"); - LoadInst *CTX_load = IRB.CreateLoad( + LoadInst *CTX_load = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - IRB.getInt32Ty(), + IRB.getInt32Ty(), #endif - CTX_add); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); - - ++select_cnt; + CTX_add); + val1 = IRB.CreateAdd(val1, CTX_load); + val2 = IRB.CreateAdd(val2, CTX_load); - if (t->getTypeID() == llvm::Type::IntegerTyID) { + } - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val11 = IRB.CreateAdd(val1, CTX_load); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val22 = IRB.CreateAdd(val2, CTX_load); - result = IRB.CreateSelect(condition, val11, val22); - skip_next = 1; - inst += 2; + result = IRB.CreateSelect(condition, val1, val2); + skip_next = 1; + inst += 2; - } else + } else #if LLVM_VERSION_MAJOR >= 14 - if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + if (t->getTypeID() == llvm::Type::FixedVectorTyID) { - FixedVectorType *tt = dyn_cast(t); - if (tt) { + FixedVectorType *tt = dyn_cast(t); + if (tt) { - uint32_t elements = tt->getElementCount().getFixedValue(); - vector_cnt = elements; - inst += vector_cnt * 2; + uint32_t elements = tt->getElementCount().getFixedValue(); + vector_cnt = elements; + inst += vector_cnt * 2; + if (elements) { + + FixedVectorType *GuardPtr1 = + FixedVectorType::get(Int32Ty, elements); + FixedVectorType *GuardPtr2 = + FixedVectorType::get(Int32Ty, elements); + Value *x, *y; + + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + if (CTX_add) { + + LoadInst *CTX_load = IRB.CreateLoad( + #if LLVM_VERSION_MAJOR >= 14 + IRB.getInt32Ty(), + #endif + CTX_add); + val1 = IRB.CreateAdd(val1, CTX_load); + val2 = IRB.CreateAdd(val2, CTX_load); - if (elements) { + } - FixedVectorType *GuardPtr1 = - FixedVectorType::get(Int32Ty, elements); - FixedVectorType *GuardPtr2 = - FixedVectorType::get(Int32Ty, elements); - Value *x, *y; + x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); + y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val11 = IRB.CreateAdd(val1, CTX_load); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val22 = IRB.CreateAdd(val2, CTX_load); - x = IRB.CreateInsertElement(GuardPtr1, val11, (uint64_t)0); - y = IRB.CreateInsertElement(GuardPtr2, val22, (uint64_t)0); + for (uint64_t i = 1; i < elements; i++) { - for (uint64_t i = 1; i < elements; i++) { + val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + /*if (CTX_add) { // already loaded I guess - val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - val11 = IRB.CreateAdd(val1, CTX_load); - val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - val11 = IRB.CreateAdd(val1, CTX_load); - x = IRB.CreateInsertElement(GuardPtr1, val11, i); - y = IRB.CreateInsertElement(GuardPtr2, val22, i); + LoadInst *CTX_load = IRB.CreateLoad( + #if LLVM_VERSION_MAJOR >= 14 + IRB.getInt32Ty(), + #endif + CTX_add); + val1 = IRB.CreateAdd(val1, CTX_load); + val2 = IRB.CreateAdd(val2, CTX_load); - } + }*/ - result = IRB.CreateSelect(condition, x, y); - skip_next = 1; + x = IRB.CreateInsertElement(GuardPtr1, val1, i); + y = IRB.CreateInsertElement(GuardPtr2, val2, i); } + result = IRB.CreateSelect(condition, x, y); + skip_next = 1; + } - } else + } + + } else #endif - { + { - unhandled++; - continue; + ++unhandled; + continue; - } + } - uint32_t vector_cur = 0; - /* Load SHM pointer */ - LoadInst *MapPtr = - IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); + uint32_t vector_cur = 0; + /* Load SHM pointer */ + LoadInst *MapPtr = + IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); - while (1) { + while (1) { - /* Get CurLoc */ - Value *MapPtrIdx = nullptr; + /* Get CurLoc */ + Value *MapPtrIdx = nullptr; - /* Load counter for CurLoc */ - if (!vector_cnt) { + /* Load counter for CurLoc */ + if (!vector_cnt) { - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); - } else { + } else { - auto element = IRB.CreateExtractElement(result, vector_cur++); - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); + auto element = IRB.CreateExtractElement(result, vector_cur++); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); - } + } - if (use_threadsafe_counters) { + if (use_threadsafe_counters) { - auto nosan = IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, - MapPtrIdx, One, + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, #if LLVM_VERSION_MAJOR >= 13 - llvm::MaybeAlign(1), + llvm::MaybeAlign(1), #endif - llvm::AtomicOrdering::Monotonic); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); - - } else { - - LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); + llvm::AtomicOrdering::Monotonic); - /* Update bitmap */ + } else { - Value *Incr = IRB.CreateAdd(Counter, One); + LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); - if (skip_nozero == NULL) { + /* Update bitmap */ - auto cf = IRB.CreateICmpEQ(Incr, Zero); - auto carry = IRB.CreateZExt(cf, Int8Ty); - Incr = IRB.CreateAdd(Incr, carry); + Value *Incr = IRB.CreateAdd(Counter, One); - } + if (skip_nozero == NULL) { - auto nosan = IRB.CreateStore(Incr, MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); + auto cf = IRB.CreateICmpEQ(Incr, Zero); + auto carry = IRB.CreateZExt(cf, Int8Ty); + Incr = IRB.CreateAdd(Incr, carry); } - if (!vector_cnt || vector_cnt == vector_cur) { break; } + auto nosan = IRB.CreateStore(Incr, MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); } - skip_next = 1; + if (!vector_cnt || vector_cnt == vector_cur) { break; } - } else { + } - skip_next = 0; + skip_next = 1; - } + } else { + + skip_next = 0; } } - // if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) - // BlocksToInstrument.push_back(&BB); + // if (shouldInstrumentBlock(F, &BB, DT, PDT, Options)) + // BlocksToInstrument.push_back(&BB); + + /* + for (auto &Inst : BB) { + + if (Options.IndirectCalls) { + + CallBase *CB = dyn_cast(&Inst); + if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst); + + } + + }*/ } @@ -1717,6 +1870,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( stderr, "BUG! inst_in_this_func %u != afl_global_id %u - save_global %u\n", inst_in_this_func, afl_global_id, save_global); + exit(-1); } @@ -1725,24 +1879,6 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } - /* - fprintf(stderr, "FUNCTION: %s [%u]\n", F.getName().str().c_str(), - extra_ctx_inst); int n = 0; for (auto &BB : F) { - - fprintf(stderr, "BB %d\n", n++); - for (auto &IN : BB) { - - std::string Str; - llvm::raw_string_ostream RSO(Str); - IN.print(RSO); - errs() << RSO.str() << "\n"; - - } - - } - - */ - } GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection( @@ -1867,7 +2003,6 @@ bool ModuleSanitizerCoverageLTO::InjectCoverage( } -// Fake InjectCoverage to count the instrumentations bool ModuleSanitizerCoverageLTO::Fake_InjectCoverage( Function &F, ArrayRef AllBlocks, bool IsLeafFunc) { @@ -1875,7 +2010,6 @@ bool ModuleSanitizerCoverageLTO::Fake_InjectCoverage( for (size_t i = 0, N = AllBlocks.size(); i < N; i++) { - // AFL++ START if (BlockList.size()) { int skip = 0; @@ -1904,6 +2038,7 @@ bool ModuleSanitizerCoverageLTO::Fake_InjectCoverage( // The cache is used to speed up recording the caller-callee pairs. // The address of the caller is passed implicitly via caller PC. // CacheSize is encoded in the name of the run-time function. +/* void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls( Function &F, ArrayRef IndirCalls) { @@ -1922,6 +2057,8 @@ void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls( } +*/ + void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx, @@ -1968,13 +2105,19 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, /* Set the ID of the inserted basic block */ ConstantInt *CurLoc = ConstantInt::get(Int32Tyi, afl_global_id); - LoadInst *CTX_load = IRB.CreateLoad( + Value *val = CurLoc; + + if (CTX_add) { + + LoadInst *CTX_load = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - IRB.getInt32Ty(), + IRB.getInt32Ty(), #endif - CTX_add); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); - Value *offset = IRB.CreateAdd(CurLoc, CTX_load); + CTX_add); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(CTX_load); + val = IRB.CreateAdd(CurLoc, CTX_load); + + } /* Load SHM pointer */ @@ -1982,13 +2125,13 @@ void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F, if (map_addr) { - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, offset); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, val); } else { LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, offset); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, val); } -- cgit 1.4.1 From bd13d32437ebf0c1f7304dc4c8f9797dc4cce7fb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 2 Feb 2024 09:54:24 +0100 Subject: final touches --- instrumentation/SanitizerCoverageLTO.so.cc | 299 ++++++++++++++++++----------- src/afl-cc.c | 2 - 2 files changed, 185 insertions(+), 116 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index f6d60099..31d26ca3 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -1394,10 +1394,14 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( uint32_t inst_save = inst, save_global = afl_global_id; uint32_t inst_in_this_func = 0; Function *caller = NULL; + LoadInst *PrevCtxLoad = NULL; CTX_add = NULL; - if (debug) fprintf(stderr, "Function: %s\n", F.getName().str().c_str()); + if (debug) + fprintf(stderr, + "Function: %s (%u %u) XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n", + F.getName().str().c_str(), inst, afl_global_id); if (instrument_ctx) { @@ -1585,7 +1589,8 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( Value *CTX_offset; BasicBlock::iterator IP = BB.getFirstInsertionPt(); IRBuilder<> IRB(&(*IP)); - LoadInst *PrevCtxLoad = IRB.CreateLoad( + + PrevCtxLoad = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 IRB.getInt32Ty(), #endif @@ -1608,20 +1613,78 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } - } + // bool loaded = false, multicall = false; + for (auto &IN : BB) { + + // check all calls and where callee count == 1 instrument + // our current caller_id to __afl_ctx + if (auto callInst = dyn_cast(&IN)) { - inst = inst_save; + Function *Callee = callInst->getCalledFunction(); + if (countCallers(Callee) == 1) { + + if (debug) + fprintf(stderr, "DEBUG: %s call to %s with only one caller\n", + F.getName().str().c_str(), + Callee->getName().str().c_str()); + /* if (loaded == false || multicall == true) { // } */ + IRBuilder<> Builder(IN.getContext()); + Builder.SetInsertPoint(callInst); + StoreInst *StoreCtx = + Builder.CreateStore(PrevCtxLoad, AFLContext); + StoreCtx->setMetadata("nosanitize", N); + // multicall = false; loaded = true; + + } // else { multicall = true; } + + } + + } + + } } } + inst = inst_save; + } + /* if (debug) + fprintf(stderr, "Next instrumentation (%u-%u=%u %u-%u=%u)\n", inst, + inst_save, inst - inst_save, afl_global_id, save_global, + afl_global_id - save_global);*/ + for (auto &BB : F) { + skip_next = 0; + + /* + uint32_t j = 0; + fprintf(stderr, "BB %p ============================================\n", + CTX_add);*/ + for (auto &IN : BB) { + /* j++; + uint32_t i = 1; + std::string errMsg; + raw_string_ostream os(errMsg); + IN.print(os); + fprintf(stderr, "Next instruction, BB size now %zu: %02u %s\n", + BB.size(), j, os.str().c_str()); for (auto &IN2 : BB) { + + std::string errMsg2; + raw_string_ostream os2(errMsg2); + IN2.print(os2); + fprintf( + stderr, "%s %02u: %s\n", + strcmp(os.str().c_str(), os2.str().c_str()) == 0 ? ">>>" : " + ", i++, os2.str().c_str()); + + }*/ + CallInst *callInst = nullptr; if ((callInst = dyn_cast(&IN))) { @@ -1665,83 +1728,62 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( SelectInst *selectInst = nullptr; - /* - std::string errMsg; - raw_string_ostream os(errMsg); - IN.print(os); - fprintf(stderr, "X(%u): %s\n", skip_next, os.str().c_str()); - */ - if (!skip_next && (selectInst = dyn_cast(&IN))) { - - uint32_t vector_cnt = 0; - Value *condition = selectInst->getCondition(); - Value *result; - auto t = condition->getType(); - IRBuilder<> IRB(selectInst->getNextNode()); + if ((selectInst = dyn_cast(&IN))) { - ++select_cnt; + if (!skip_next) { - if (t->getTypeID() == llvm::Type::IntegerTyID) { + // fprintf(stderr, "Select in\n"); - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - if (CTX_add) { - - LoadInst *CTX_load = IRB.CreateLoad( -#if LLVM_VERSION_MAJOR >= 14 - IRB.getInt32Ty(), -#endif - CTX_add); - val1 = IRB.CreateAdd(val1, CTX_load); - val2 = IRB.CreateAdd(val2, CTX_load); + uint32_t vector_cnt = 0; + Value *condition = selectInst->getCondition(); + Value *result; + auto t = condition->getType(); + IRBuilder<> IRB(selectInst->getNextNode()); - } + ++select_cnt; - result = IRB.CreateSelect(condition, val1, val2); - skip_next = 1; - inst += 2; + if (t->getTypeID() == llvm::Type::IntegerTyID) { - } else + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + if (CTX_add) { + LoadInst *CTX_load = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 - if (t->getTypeID() == llvm::Type::FixedVectorTyID) { - - FixedVectorType *tt = dyn_cast(t); - if (tt) { + IRB.getInt32Ty(), +#endif + CTX_add); + val1 = IRB.CreateAdd(val1, CTX_load); + val2 = IRB.CreateAdd(val2, CTX_load); - uint32_t elements = tt->getElementCount().getFixedValue(); - vector_cnt = elements; - inst += vector_cnt * 2; - if (elements) { + } - FixedVectorType *GuardPtr1 = - FixedVectorType::get(Int32Ty, elements); - FixedVectorType *GuardPtr2 = - FixedVectorType::get(Int32Ty, elements); - Value *x, *y; + result = IRB.CreateSelect(condition, val1, val2); + skip_next = 1; + inst += 2; - Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - if (CTX_add) { + } else - LoadInst *CTX_load = IRB.CreateLoad( - #if LLVM_VERSION_MAJOR >= 14 - IRB.getInt32Ty(), - #endif - CTX_add); - val1 = IRB.CreateAdd(val1, CTX_load); - val2 = IRB.CreateAdd(val2, CTX_load); +#if LLVM_VERSION_MAJOR >= 14 + if (t->getTypeID() == llvm::Type::FixedVectorTyID) { - } + FixedVectorType *tt = dyn_cast(t); + if (tt) { - x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); - y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); + uint32_t elements = tt->getElementCount().getFixedValue(); + vector_cnt = elements; + inst += vector_cnt * 2; + if (elements) { - for (uint64_t i = 1; i < elements; i++) { + FixedVectorType *GuardPtr1 = + FixedVectorType::get(Int32Ty, elements); + FixedVectorType *GuardPtr2 = + FixedVectorType::get(Int32Ty, elements); + Value *x, *y; - val1 = ConstantInt::get(Int32Ty, ++afl_global_id); - val2 = ConstantInt::get(Int32Ty, ++afl_global_id); - /*if (CTX_add) { // already loaded I guess + Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + if (CTX_add) { LoadInst *CTX_load = IRB.CreateLoad( #if LLVM_VERSION_MAJOR >= 14 @@ -1751,92 +1793,116 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( val1 = IRB.CreateAdd(val1, CTX_load); val2 = IRB.CreateAdd(val2, CTX_load); - }*/ + } - x = IRB.CreateInsertElement(GuardPtr1, val1, i); - y = IRB.CreateInsertElement(GuardPtr2, val2, i); + x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); + y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); - } + for (uint64_t i = 1; i < elements; i++) { - result = IRB.CreateSelect(condition, x, y); - skip_next = 1; + val1 = ConstantInt::get(Int32Ty, ++afl_global_id); + val2 = ConstantInt::get(Int32Ty, ++afl_global_id); + /*if (CTX_add) { // already loaded I guess - } + LoadInst *CTX_load = IRB.CreateLoad( + #if LLVM_VERSION_MAJOR >= 14 + IRB.getInt32Ty(), + #endif + CTX_add); + val1 = IRB.CreateAdd(val1, CTX_load); + val2 = IRB.CreateAdd(val2, CTX_load); - } + }*/ + + x = IRB.CreateInsertElement(GuardPtr1, val1, i); + y = IRB.CreateInsertElement(GuardPtr2, val2, i); + + } + + result = IRB.CreateSelect(condition, x, y); + skip_next = 1; - } else + } + + } + + } else #endif - { + { - ++unhandled; - continue; + ++unhandled; + continue; - } + } - uint32_t vector_cur = 0; - /* Load SHM pointer */ - LoadInst *MapPtr = - IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); + uint32_t vector_cur = 0; + /* Load SHM pointer */ + LoadInst *MapPtr = + IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr); - while (1) { + while (1) { - /* Get CurLoc */ - Value *MapPtrIdx = nullptr; + /* Get CurLoc */ + Value *MapPtrIdx = nullptr; - /* Load counter for CurLoc */ - if (!vector_cnt) { + /* Load counter for CurLoc */ + if (!vector_cnt) { - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result); - } else { + } else { - auto element = IRB.CreateExtractElement(result, vector_cur++); - MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); + auto element = IRB.CreateExtractElement(result, vector_cur++); + MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element); - } + } - if (use_threadsafe_counters) { + if (use_threadsafe_counters) { - IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One, + IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, + One, #if LLVM_VERSION_MAJOR >= 13 - llvm::MaybeAlign(1), + llvm::MaybeAlign(1), #endif - llvm::AtomicOrdering::Monotonic); + llvm::AtomicOrdering::Monotonic); + + } else { - } else { + LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); - LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter); + /* Update bitmap */ - /* Update bitmap */ + 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); + } + + auto nosan = IRB.CreateStore(Incr, MapPtrIdx); + ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); } - auto nosan = IRB.CreateStore(Incr, MapPtrIdx); - ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan); + if (!vector_cnt || vector_cnt == vector_cur) { break; } } - if (!vector_cnt || vector_cnt == vector_cur) { break; } - - } + skip_next = 1; + // fprintf(stderr, "Select out\n"); - skip_next = 1; + } else { - } else { + // fprintf(stderr, "Select skip\n"); + skip_next = 0; - skip_next = 0; + } } @@ -1862,6 +1928,11 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( InjectCoverage(F, BlocksToInstrument, IsLeafFunc); // InjectCoverageForIndirectCalls(F, IndirCalls); + /*if (debug) + fprintf(stderr, "Done instrumentation (%u-%u=%u %u-%u=%u)\n", inst, + inst_save, inst - inst_save, afl_global_id, save_global, + afl_global_id - save_global);*/ + if (inst_in_this_func && call_counter > 1) { if (inst_in_this_func != afl_global_id - save_global) { diff --git a/src/afl-cc.c b/src/afl-cc.c index 4f6745ed..fd466541 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -1103,8 +1103,6 @@ static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) { } - fprintf(stderr, "X %u %u\n", aflcc->compiler_mode, LTO); - if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM && !((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) && aflcc->compiler_mode == LTO)) -- cgit 1.4.1 From ba3a039e457025399f7b58905d3923d068ef0eef Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 2 Feb 2024 13:17:20 +0100 Subject: finish lto-ctx --- instrumentation/SanitizerCoverageLTO.so.cc | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 31d26ca3..65602109 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -250,7 +250,7 @@ class ModuleSanitizerCoverageLTO uint32_t afl_global_id = 0; uint32_t unhandled = 0; uint32_t select_cnt = 0; - uint32_t instrument_ctx = 1; + uint32_t instrument_ctx = 0; uint32_t extra_ctx_inst = 0; uint64_t map_addr = 0; const char *skip_nozero = NULL; @@ -771,12 +771,12 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( else Str2 = TmpStr.str(); - if (debug) + /*if (debug) fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n", FuncName.c_str(), Str1P, Str1P->getName().str().c_str(), Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P, Str2P->getName().str().c_str(), Str2.c_str(), - HasStr2 == true ? "true" : "false"); + HasStr2 == true ? "true" : "false");*/ // we handle the 2nd parameter first because of llvm memcpy if (!HasStr2) { @@ -1398,10 +1398,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( CTX_add = NULL; - if (debug) - fprintf(stderr, - "Function: %s (%u %u) XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n", - F.getName().str().c_str(), inst, afl_global_id); + if (debug) fprintf(stderr, "Function: %s\n", F.getName().str().c_str()); if (instrument_ctx) { @@ -1613,7 +1610,6 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } - // bool loaded = false, multicall = false; for (auto &IN : BB) { // check all calls and where callee count == 1 instrument @@ -1627,15 +1623,14 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( fprintf(stderr, "DEBUG: %s call to %s with only one caller\n", F.getName().str().c_str(), Callee->getName().str().c_str()); - /* if (loaded == false || multicall == true) { // } */ + IRBuilder<> Builder(IN.getContext()); Builder.SetInsertPoint(callInst); StoreInst *StoreCtx = Builder.CreateStore(PrevCtxLoad, AFLContext); StoreCtx->setMetadata("nosanitize", N); - // multicall = false; loaded = true; - } // else { multicall = true; } + } } -- cgit 1.4.1 From d85722a4f6329940545dd66bf16718d591fca681 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 3 Feb 2024 13:31:31 +0100 Subject: deterministic fuzzing and -z --- docs/Changelog.md | 5 +++++ src/afl-fuzz-state.c | 2 +- src/afl-fuzz.c | 19 +++++++------------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 48003f4b..2f0fba33 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -3,6 +3,11 @@ This is the list of all noteworthy changes made in every public release of the tool. See README.md for the general instruction manual. +### Version ++4.20a (dev) + - afl-fuzz: + - the new deterministic fuzzing feature is now activated by default, + deactivate with -z. Parameters -d and -D are ignored. + ### Version ++4.10c (release) - afl-fuzz: - default power schedule is now EXPLORE, due a fix in fast schedules diff --git a/src/afl-fuzz-state.c b/src/afl-fuzz-state.c index 4467cae8..ae327117 100644 --- a/src/afl-fuzz-state.c +++ b/src/afl-fuzz-state.c @@ -102,7 +102,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) { afl->stats_update_freq = 1; afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000; afl->stats_avg_exec = 0; - afl->skip_deterministic = 1; + afl->skip_deterministic = 0; afl->sync_time = SYNC_TIME; afl->cmplog_lvl = 2; afl->min_length = 1; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 12d67fe7..b556b4b6 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -170,7 +170,6 @@ static void usage(u8 *argv0, int more_help) { " -g minlength - set min length of generated fuzz input (default: 1)\n" " -G maxlength - set max length of generated fuzz input (default: " "%lu)\n" - " -D - enable (a new) effective deterministic fuzzing\n" " -L minutes - use MOpt(imize) mode and set the time limit for " "entering the\n" " pacemaker mode (minutes of no new finds). 0 = " @@ -213,7 +212,8 @@ static void usage(u8 *argv0, int more_help) { " -F path - sync to a foreign fuzzer queue directory (requires " "-M, can\n" " be specified up to %u times)\n" - // " -d - skip deterministic fuzzing in -M mode\n" + " -z - skip the enhanced deterministic fuzzing\n" + " (note that the old -d and -D flags are ignored.)\n" " -T text - text banner to show on the screen\n" " -I command - execute this command/script when a new crash is " "found\n" @@ -955,20 +955,15 @@ int main(int argc, char **argv_orig, char **envp) { break; - case 'D': /* partial deterministic */ + case 'd': + case 'D': /* old deterministic */ - afl->skip_deterministic = 0; + WARNF("Parameters -d and -D are deprecated, a new enhanced deterministic fuzzing is active by default, to disable it use -z"); break; - case 'd': /* no deterministic */ + case 'z': /* no deterministic */ - // this is the default and currently a lot of infrastructure enforces - // it (e.g. clusterfuzz, fuzzbench) based on that this feature - // originally was bad performance wise. We now have a better - // implementation, hence if it is activated, we do not want to - // deactivate it by such setups. - - // afl->skip_deterministic = 1; + afl->skip_deterministic = 1; break; case 'B': /* load bitmap */ -- cgit 1.4.1 From dc151caa1839162e470e003837e630db6d5d543e Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 3 Feb 2024 15:53:54 +0100 Subject: add lto caller instrumentation --- docs/Changelog.md | 5 +++++ docs/env_variables.md | 3 +++ instrumentation/SanitizerCoverageLTO.so.cc | 27 ++++++++++++++++++++++++--- src/afl-cc.c | 5 +++-- 4 files changed, 35 insertions(+), 5 deletions(-) diff --git a/docs/Changelog.md b/docs/Changelog.md index 2f0fba33..e5169daf 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -7,6 +7,11 @@ - afl-fuzz: - the new deterministic fuzzing feature is now activated by default, deactivate with -z. Parameters -d and -D are ignored. + - afl-cc: + - added collision free caller instrumentation to LTO mode. activate with + `AFL_LLVM_LTO_CALLER=1`. You can set a max depth to go through single + block functions with `AFL_LLVM_LTO_CALLER_DEPTH` (default 0) + ### Version ++4.10c (release) - afl-fuzz: diff --git a/docs/env_variables.md b/docs/env_variables.md index a972b6da..1e4fc7ba 100644 --- a/docs/env_variables.md +++ b/docs/env_variables.md @@ -248,6 +248,9 @@ use (which only ever the author of this LTO implementation will use). These are used if several separated instrumentations are performed which are then later combined. + - `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation + - `AFL_LLVM_LTO_CALLER` sets the maximum mumber of single block functions + to dig deeper into a real function. Default 0. - `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given to which function. This helps to identify functions with variable bytes or which functions were touched by an input. diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index 65602109..b93b72bf 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -251,6 +251,7 @@ class ModuleSanitizerCoverageLTO uint32_t unhandled = 0; uint32_t select_cnt = 0; uint32_t instrument_ctx = 0; + uint32_t instrument_ctx_max_depth = 0; uint32_t extra_ctx_inst = 0; uint64_t map_addr = 0; const char *skip_nozero = NULL; @@ -428,12 +429,31 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( setvbuf(stdout, NULL, _IONBF, 0); if (getenv("AFL_DEBUG")) { debug = 1; } if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; } - if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_CTX")) { + if (getenv("AFL_LLVM_CALLER") || getenv("AFL_LLVM_CTX") || + getenv("AFL_LLVM_LTO_CALLER") || getenv("AFL_LLVM_LTO_CTX")) { instrument_ctx = 1; } + if (getenv("AFL_LLVM_LTO_CALLER_DEPTH")) { + + instrument_ctx_max_depth = atoi(getenv("AFL_LLVM_LTO_CALLER_DEPTH")); + + } else if (getenv("AFL_LLVM_LTO_CTX_DEPTH")) { + + instrument_ctx_max_depth = atoi(getenv("AFL_LLVM_LTO_CTX_DEPTH")); + + } else if (getenv("AFL_LLVM_CALLER_DEPTH")) { + + instrument_ctx_max_depth = atoi(getenv("AFL_LLVM_CALLER_DEPTH")); + + } else if (getenv("AFL_LLVM_CTX_DEPTH")) { + + instrument_ctx_max_depth = atoi(getenv("AFL_LLVM_CTX_DEPTH")); + + } + if ((isatty(2) && !getenv("AFL_QUIET")) || debug) { SAYF(cCYA "afl-llvm-lto" VERSION cRST @@ -1406,11 +1426,12 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( call_counter = countCallers(caller); Function *callee = caller; - if (call_counter == 1) { + if (call_counter == 1 && instrument_ctx_max_depth) { ++call_depth; - while (((caller = returnOnlyCaller(callee)) || 1 == 1) && + while (instrument_ctx_max_depth >= call_depth && + ((caller = returnOnlyCaller(callee)) || 1 == 1) && (call_counter = countCallers(callee)) == 1) { if (debug && caller && callee) diff --git a/src/afl-cc.c b/src/afl-cc.c index 7d33b9f5..4d586ce8 100644 --- a/src/afl-cc.c +++ b/src/afl-cc.c @@ -2921,11 +2921,12 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) { " AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " "functions\n" " into this file (LTO mode)\n" + " AFL_LLVM_LTO_CALLER: activate CALLER/CTX instrumentation\n" + " AFL_LLVM_LTO_CALLER_DEPTH: skip how many empty functions\n" " AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " "global var\n" " AFL_LLVM_LTO_STARTID: from which ID to start counting from for " - "a " - "bb\n" + "a bb\n" " AFL_REAL_LD: use this lld linker instead of the compiled in " "path\n" " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code " -- cgit 1.4.1 From 9fab7e892d4e2ba09305aac40392a4df598464c9 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 3 Feb 2024 16:48:38 +0100 Subject: new forkserver - server part --- include/types.h | 7 + src/afl-forkserver.c | 368 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 274 insertions(+), 101 deletions(-) diff --git a/include/types.h b/include/types.h index 22332135..d0a2d124 100644 --- a/include/types.h +++ b/include/types.h @@ -49,6 +49,13 @@ typedef uint128_t u128; #define FS_ERROR_OLD_CMPLOG 32 #define FS_ERROR_OLD_CMPLOG_QEMU 64 +/* New Forkserver */ +#define FS_NEW_VERSION_MIN 1 +#define FS_NEW_VERSION_MAX 1 +#define FS_NEW_OPT_MAPSIZE 0x00000001 // parameter: 32 bit value +#define FS_NEW_OPT_SHDMEM_FUZZ 0x00000002 // paramter: none +#define FS_NEW_OPT_AUTODICT 0x00000800 // autodictionary data + /* Reporting options */ #define FS_OPT_ENABLED 0x80000001 #define FS_OPT_MAPSIZE 0x40000000 diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 0a77d61c..1f796e53 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -389,7 +389,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) { while (1) { uint32_t was_killed; - int status; + u32 status; /* Wait for parent by reading from the pipe. Exit if read fails. */ @@ -524,7 +524,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output) { int st_pipe[2], ctl_pipe[2]; - s32 status; + u32 status; s32 rlen; char *ignore_autodict = getenv("AFL_NO_AUTODICT"); @@ -1017,69 +1017,95 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (rlen == 4) { + /* + * The new fork server model works like this: + * Client: sends "AFLx" in little endian, with x being the forkserver + * protocol version. + * Server: replies with XOR of the message or exits with an error if it + * is not a supported version. + * Client: sends 32 bit of options and then sends all parameters of + * the options, one after another, increasing by option number. + * Ends with "AFLx". + * After the initial protocol version confirmation the server does not + * send any data anymore - except a future option requires this. + */ + if (status >= 0x41464c00 && status <= 0x41464cff) { - FATAL( - "Target uses the new forkserver model, you need to switch to a newer " - "afl-fuzz too!"); + u32 version = status - 0x41464c00; - } + if (!version) { - if (!be_quiet) { OKF("All right - fork server is up."); } + FATAL( + "Fork server version is not assigned, this should not happen. " + "Recompile target."); - if (getenv("AFL_DEBUG")) { + } else if (version < FS_NEW_VERSION_MIN || version > FS_NEW_VERSION_MAX) { - ACTF("Extended forkserver functions received (%08x).", status); + FATAL( + "Fork server version is not not supported. Recompile the target."); - } + } - if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) - report_error_and_exit(FS_OPT_GET_ERROR(status)); + status ^= 0xffffffff; + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { + FATAL("Writing to forkserver failed."); - // workaround for recent AFL++ versions - if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND) - status = (status & 0xf0ffffff); + } - if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) { + if (!be_quiet) { - if (fsrv->qemu_mode || fsrv->frida_mode) { + OKF("All right - new fork server model v%u is up.", version); - report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU); + } - } else { + rlen = read(fsrv->fsrv_st_fd, &status, 4); - report_error_and_exit(FS_ERROR_OLD_CMPLOG); + if (getenv("AFL_DEBUG")) { - } + ACTF("Forkserver options received: (%08x)", status); } - if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + if ((status & FS_NEW_OPT_MAPSIZE)) { - fsrv->snapshot = 1; - if (!be_quiet) { ACTF("Using SNAPSHOT feature."); } + u32 tmp_map_size; + rlen = read(fsrv->fsrv_st_fd, &tmp_map_size, 4); - } + if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { + fsrv->real_map_size = tmp_map_size; - if (fsrv->support_shmem_fuzz) { + if (tmp_map_size % 64) { - fsrv->use_shmem_fuzz = 1; - if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } + tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); + + } - if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) { + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } + if (tmp_map_size > fsrv->map_size) { - u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); - if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { + FATAL( + "Target's coverage map size of %u is larger than the one this " + "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and " + "restart " + " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " + "afl-fuzz", + tmp_map_size, fsrv->map_size, tmp_map_size); - FATAL("Writing to forkserver failed."); + } - } + fsrv->map_size = tmp_map_size; - } + } + + if ((status & FS_NEW_OPT_SHDMEM_FUZZ)) { + + if (fsrv->support_shmem_fuzz) { + + fsrv->use_shmem_fuzz = 1; + if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } } else { @@ -1091,134 +1117,274 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } - if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { + if ((status & FS_NEW_OPT_AUTODICT)) { - u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); + u32 dict_size; + if (read(fsrv->fsrv_st_fd, &dict_size, 4) != 4) { - if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } + FATAL("Reading from forkserver failed."); - fsrv->real_map_size = tmp_map_size; + } - if (tmp_map_size % 64) { + if (dict_size < 2 || dict_size > 0xffffff) { - tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); + FATAL("Dictionary has an illegal size: %d", dict_size); } - if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } - if (tmp_map_size > fsrv->map_size) { + u32 offset = 0, count = 0; + u8 *dict = ck_alloc(dict_size); + if (dict == NULL) { - FATAL( - "Target's coverage map size of %u is larger than the one this " - "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " - " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " - "afl-fuzz", - tmp_map_size, fsrv->map_size, tmp_map_size); + FATAL("Could not allocate %u bytes of autodictionary memory", + dict_size); } - fsrv->map_size = tmp_map_size; + while (dict_size != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size); + if (rlen > 0) { + + dict_size -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, dict_size); + + } + + } + + offset = 0; + while (offset < dict_size && (u8)dict[offset] + offset < dict_size) { + + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } + ck_free(dict); } - if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { + u32 status2; + rlen = read(fsrv->fsrv_st_fd, &status2, 4); - if (!ignore_autodict) { + if (status2 != status) { FATAL("Error in forkserver communication"); } - if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { + } else { - // this is not afl-fuzz - or it is cmplog - we deny and return - if (fsrv->use_shmem_fuzz) { + WARNF( + "Old fork server model is used by the target, this still works " + "though."); - status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + if (!be_quiet) { OKF("All right - old fork server is up."); } - } else { + if (getenv("AFL_DEBUG")) { - status = (FS_OPT_ENABLED); + ACTF("Extended forkserver functions received (%08x).", status); - } + } - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) + report_error_and_exit(FS_OPT_GET_ERROR(status)); - FATAL("Writing to forkserver failed."); + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { - } + // workaround for recent AFL++ versions + if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == + FS_OPT_OLD_AFLPP_WORKAROUND) + status = (status & 0xf0ffffff); + + if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) { + + if (fsrv->qemu_mode || fsrv->frida_mode) { + + report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU); + + } else { - return; + report_error_and_exit(FS_ERROR_OLD_CMPLOG); } - if (!be_quiet) { ACTF("Using AUTODICT feature."); } + } + + if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { + + fsrv->snapshot = 1; + if (!be_quiet) { ACTF("Using SNAPSHOT feature."); } + + } + + if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { + + if (fsrv->support_shmem_fuzz) { + + fsrv->use_shmem_fuzz = 1; + if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); } + + if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) { - if (fsrv->use_shmem_fuzz) { + u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) { - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); + FATAL("Writing to forkserver failed."); + + } + + } } else { - status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); + FATAL( + "Target requested sharedmem fuzzing, but we failed to enable " + "it."); } - if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + } - FATAL("Writing to forkserver failed."); + if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { - } + u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); - if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { + if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } - FATAL("Reading from forkserver failed."); + fsrv->real_map_size = tmp_map_size; + + if (tmp_map_size % 64) { + + tmp_map_size = (((tmp_map_size + 63) >> 6) << 6); } - if (status < 2 || (u32)status > 0xffffff) { + if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); } + if (tmp_map_size > fsrv->map_size) { - FATAL("Dictionary has an illegal size: %d", status); + FATAL( + "Target's coverage map size of %u is larger than the one this " + "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and " + "restart " + " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " + "afl-fuzz", + tmp_map_size, fsrv->map_size, tmp_map_size); } - u32 offset = 0, count = 0; - u32 len = status; - u8 *dict = ck_alloc(len); - if (dict == NULL) { + fsrv->map_size = tmp_map_size; + + } - FATAL("Could not allocate %u bytes of autodictionary memory", len); + if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { - } + if (!ignore_autodict) { - while (len != 0) { + if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { - rlen = read(fsrv->fsrv_st_fd, dict + offset, len); - if (rlen > 0) { + // this is not afl-fuzz - or it is cmplog - we deny and return + if (fsrv->use_shmem_fuzz) { - len -= rlen; - offset += rlen; + status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); + + } else { + + status = (FS_OPT_ENABLED); + + } + + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { + + FATAL("Writing to forkserver failed."); + + } + + return; + + } + + if (!be_quiet) { ACTF("Using AUTODICT feature."); } + + if (fsrv->use_shmem_fuzz) { + + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ); } else { - FATAL( - "Reading autodictionary fail at position %u with %u bytes " - "left.", - offset, len); + status = (FS_OPT_ENABLED | FS_OPT_AUTODICT); } - } + if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { - offset = 0; - while (offset < (u32)status && - (u8)dict[offset] + offset < (u32)status) { + FATAL("Writing to forkserver failed."); - fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, - (u8)dict[offset]); - offset += (1 + dict[offset]); - count++; + } - } + if (read(fsrv->fsrv_st_fd, &status, 4) != 4) { - if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } - ck_free(dict); + FATAL("Reading from forkserver failed."); + + } + + if (status < 2 || (u32)status > 0xffffff) { + + FATAL("Dictionary has an illegal size: %d", status); + + } + + u32 offset = 0, count = 0; + u32 len = status; + u8 *dict = ck_alloc(len); + if (dict == NULL) { + + FATAL("Could not allocate %u bytes of autodictionary memory", + len); + + } + + while (len != 0) { + + rlen = read(fsrv->fsrv_st_fd, dict + offset, len); + if (rlen > 0) { + + len -= rlen; + offset += rlen; + + } else { + + FATAL( + "Reading autodictionary fail at position %u with %u bytes " + "left.", + offset, len); + + } + + } + + offset = 0; + while (offset < (u32)status && + (u8)dict[offset] + offset < (u32)status) { + + fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, + (u8)dict[offset]); + offset += (1 + dict[offset]); + count++; + + } + + if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); } + ck_free(dict); + + } } -- cgit 1.4.1 From 27338fcef121c7700a1e2e99cb31cb7106159293 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 3 Feb 2024 18:27:01 +0100 Subject: new forkserver - client side --- include/types.h | 7 +- instrumentation/afl-compiler-rt.o.c | 414 ++++++------------------------------ src/afl-forkserver.c | 15 +- 3 files changed, 80 insertions(+), 356 deletions(-) diff --git a/include/types.h b/include/types.h index d0a2d124..18c5df91 100644 --- a/include/types.h +++ b/include/types.h @@ -52,9 +52,10 @@ typedef uint128_t u128; /* New Forkserver */ #define FS_NEW_VERSION_MIN 1 #define FS_NEW_VERSION_MAX 1 -#define FS_NEW_OPT_MAPSIZE 0x00000001 // parameter: 32 bit value -#define FS_NEW_OPT_SHDMEM_FUZZ 0x00000002 // paramter: none -#define FS_NEW_OPT_AUTODICT 0x00000800 // autodictionary data +#define FS_NEW_ERROR 0xeffe0000 +#define FS_NEW_OPT_MAPSIZE 0x00000001 // parameter: 32 bit value +#define FS_NEW_OPT_SHDMEM_FUZZ 0x00000002 // parameter: none +#define FS_NEW_OPT_AUTODICT 0x00000800 // autodictionary data /* Reporting options */ #define FS_OPT_ENABLED 0x80000001 diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index caa3c3a8..c342334c 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -264,7 +264,7 @@ static void send_forkserver_error(int error) { u32 status; if (!error || error > 0xffff) return; - status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); + status = (FS_NEW_ERROR | error); if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; } } @@ -367,32 +367,13 @@ static void __afl_map_shm(void) { if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); } if (val < __afl_final_loc) { - if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) { + if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) { - if (!getenv("AFL_QUIET")) - fprintf(stderr, - "Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u " - "to be able to run this instrumented program!\n", - __afl_final_loc); - - if (id_str) { - - send_forkserver_error(FS_ERROR_MAP_SIZE); - exit(-1); - - } - - } else { - - if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) { - - fprintf(stderr, - "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); - - } + fprintf(stderr, + "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); } @@ -400,15 +381,6 @@ static void __afl_map_shm(void) { } - } else { - - if (getenv("AFL_DUMP_MAP_SIZE")) { - - printf("%u\n", MAP_SIZE); - exit(-1); - - } - } if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) || @@ -474,14 +446,13 @@ static void __afl_map_shm(void) { if (__afl_debug) { - fprintf( - stderr, - "DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " - "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, " - "__afl_final_loc %u, __afl_map_size %u, max_size_forkserver %u/0x%x\n", - id_str == NULL ? "" : id_str, __afl_area_ptr, __afl_area_initial, - __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, __afl_final_loc, - __afl_map_size, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE); + fprintf(stderr, + "DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " + "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, " + "__afl_final_loc %u, __afl_map_size %u\n", + id_str == NULL ? "" : id_str, __afl_area_ptr, + __afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, + __afl_final_loc, __afl_map_size); } @@ -639,12 +610,10 @@ static void __afl_map_shm(void) { fprintf(stderr, "DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE " - "%u, __afl_final_loc %u, __afl_map_size %u, " - "max_size_forkserver %u/0x%x\n", + "%u, __afl_final_loc %u, __afl_map_size %u", id_str == NULL ? "" : id_str, __afl_area_ptr, __afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, - __afl_final_loc, __afl_map_size, FS_OPT_MAX_MAPSIZE, - FS_OPT_MAX_MAPSIZE); + __afl_final_loc, __afl_map_size); } @@ -855,242 +824,6 @@ void write_error_with_location(char *text, char *filename, int linenumber) { } -#ifdef __linux__ -static void __afl_start_snapshots(void) { - - static u8 tmp[4] = {0, 0, 0, 0}; - u32 status = 0; - u32 already_read_first = 0; - u32 was_killed; - - u8 child_stopped = 0; - - void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL); - - /* Phone home and tell the parent that we're OK. If parent isn't there, - assume we're not running in forkserver mode and just execute program. */ - - status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG); - if (__afl_sharedmem_fuzzing) { status |= FS_OPT_SHDMEM_FUZZ; } - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) - status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); - if (__afl_dictionary_len && __afl_dictionary) { status |= FS_OPT_AUTODICT; } - memcpy(tmp, &status, 4); - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } - - if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { - - if (read(FORKSRV_FD, &was_killed, 4) != 4) { - - write_error("read to afl-fuzz"); - _exit(1); - - } - - if (__afl_debug) { - - fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed); - - } - - if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == - (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { - - __afl_map_shm_fuzz(); - - } - - if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == - (FS_OPT_ENABLED | FS_OPT_AUTODICT) && - __afl_dictionary_len && __afl_dictionary) { - - // great lets pass the dictionary through the forkserver FD - u32 len = __afl_dictionary_len, offset = 0; - s32 ret; - - if (write(FORKSRV_FD + 1, &len, 4) != 4) { - - write(2, "Error: could not send dictionary len\n", - strlen("Error: could not send dictionary len\n")); - _exit(1); - - } - - while (len != 0) { - - ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); - - if (ret < 1) { - - write(2, "Error: could not send dictionary\n", - strlen("Error: could not send dictionary\n")); - _exit(1); - - } - - len -= ret; - offset += ret; - - } - - } else { - - // uh this forkserver does not understand extended option passing - // or does not want the dictionary - if (!__afl_fuzz_ptr) already_read_first = 1; - - } - - } - - while (1) { - - int status; - - if (already_read_first) { - - already_read_first = 0; - - } else { - - /* Wait for parent by reading from the pipe. Abort if read fails. */ - if (read(FORKSRV_FD, &was_killed, 4) != 4) { - - write_error("reading from afl-fuzz"); - _exit(1); - - } - - } - - #ifdef _AFL_DOCUMENT_MUTATIONS - if (__afl_fuzz_ptr) { - - static uint32_t counter = 0; - char fn[32]; - sprintf(fn, "%09u:forkserver", counter); - s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION); - if (fd_doc >= 0) { - - if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) { - - fprintf(stderr, "write of mutation file failed: %s\n", fn); - unlink(fn); - - } - - close(fd_doc); - - } - - counter++; - - } - - #endif - - /* If we stopped the child in persistent mode, but there was a race - condition and afl-fuzz already issued SIGKILL, write off the old - process. */ - - if (child_stopped && was_killed) { - - child_stopped = 0; - if (waitpid(child_pid, &status, 0) < 0) { - - write_error("child_stopped && was_killed"); - _exit(1); // TODO why exit? - - } - - } - - if (!child_stopped) { - - /* Once woken up, create a clone of our process. */ - - child_pid = fork(); - if (child_pid < 0) { - - write_error("fork"); - _exit(1); - - } - - /* In child process: close fds, resume execution. */ - - if (!child_pid) { - - //(void)nice(-20); // does not seem to improve - - signal(SIGCHLD, old_sigchld_handler); - signal(SIGTERM, old_sigterm_handler); - - close(FORKSRV_FD); - close(FORKSRV_FD + 1); - - if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS | - AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) { - - raise(SIGSTOP); - - } - - __afl_area_ptr[0] = 1; - memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T)); - - return; - - } - - } else { - - /* Special handling for persistent mode: if the child is alive but - currently stopped, simply restart it with SIGCONT. */ - - kill(child_pid, SIGCONT); - child_stopped = 0; - - } - - /* In parent process: write PID to pipe, then wait for child. */ - - if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) { - - write_error("write to afl-fuzz"); - _exit(1); - - } - - if (waitpid(child_pid, &status, WUNTRACED) < 0) { - - write_error("waitpid"); - _exit(1); - - } - - /* In persistent mode, the child stops itself with SIGSTOP to indicate - a successful run. In this case, we want to wake it up without forking - again. */ - - if (WIFSTOPPED(status)) child_stopped = 1; - - /* Relay wait status to pipe, then loop back. */ - - if (write(FORKSRV_FD + 1, &status, 4) != 4) { - - write_error("writing to afl-fuzz"); - _exit(1); - - } - - } - -} - -#endif - /* Fork server logic. */ static void __afl_start_forkserver(void) { @@ -1103,113 +836,92 @@ static void __afl_start_forkserver(void) { old_sigterm_handler = orig_action.sa_handler; signal(SIGTERM, at_exit); -#ifdef __linux__ - if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") && - afl_snapshot_init() >= 0) { - - __afl_start_snapshots(); - return; - - } - -#endif - - u8 tmp[4] = {0, 0, 0, 0}; - u32 status_for_fsrv = 0; u32 already_read_first = 0; u32 was_killed; + u32 version = 0x41464c00 + FS_NEW_VERSION_MAX; + u32 tmp = version ^ 0xffffffff, status2, status = version; + u8 *msg = (u8 *)&status; + u8 *reply = (u8 *)&status2; u8 child_stopped = 0; void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL); - if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) { - - status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE); + /* Phone home and tell the parent that we're OK. If parent isn't there, + assume we're not running in forkserver mode and just execute program. */ - } + // return because possible non-forkserver usage + if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; } - if (__afl_dictionary_len && __afl_dictionary) { + if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); } + if (tmp != status2) { - status_for_fsrv |= FS_OPT_AUTODICT; + write_error("wrong forkserver message from AFL++ tool"); + _exit(1); } - if (__afl_sharedmem_fuzzing) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; } - if (status_for_fsrv) { + // send the set/requested options to forkserver + status = FS_NEW_OPT_MAPSIZE; // we always send the map size + if (__afl_sharedmem_fuzzing) { status |= FS_NEW_OPT_SHDMEM_FUZZ; } + if (__afl_dictionary_len && __afl_dictionary) { - status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG); + status |= FS_NEW_OPT_AUTODICT; } - memcpy(tmp, &status_for_fsrv, 4); + if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); } - /* Phone home and tell the parent that we're OK. If parent isn't there, - assume we're not running in forkserver mode and just execute program. */ - - if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } - - __afl_connected = 1; + // Now send the parameters for the set options, increasing by option number - if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { + // FS_NEW_OPT_MAPSIZE - we always send the map size + status = __afl_map_size; + if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); } - if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); + // FS_NEW_OPT_SHDMEM_FUZZ - no data - if (__afl_debug) { - - fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed); + // FS_NEW_OPT_AUTODICT - send autodictionary + if (__afl_dictionary_len && __afl_dictionary) { - } + // pass the dictionary through the forkserver FD + u32 len = __afl_dictionary_len, offset = 0; - if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == - (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) { + if (write(FORKSRV_FD + 1, &len, 4) != 4) { - __afl_map_shm_fuzz(); + write(2, "Error: could not send dictionary len\n", + strlen("Error: could not send dictionary len\n")); + _exit(1); } - if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == - (FS_OPT_ENABLED | FS_OPT_AUTODICT) && - __afl_dictionary_len && __afl_dictionary) { + while (len != 0) { - // great lets pass the dictionary through the forkserver FD - u32 len = __afl_dictionary_len, offset = 0; + s32 ret; + ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); - if (write(FORKSRV_FD + 1, &len, 4) != 4) { + if (ret < 1) { - write(2, "Error: could not send dictionary len\n", - strlen("Error: could not send dictionary len\n")); + write_error("could not send dictionary"); _exit(1); } - while (len != 0) { - - s32 ret; - ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len); - - if (ret < 1) { - - write(2, "Error: could not send dictionary\n", - strlen("Error: could not send dictionary\n")); - _exit(1); - - } + len -= ret; + offset += ret; - len -= ret; - offset += ret; + } - } + } - } else { + // send welcome message as final message + status = version; + if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); } - // uh this forkserver does not understand extended option passing - // or does not want the dictionary - if (!__afl_fuzz_ptr) already_read_first = 1; + // END forkserver handshake - } + __afl_connected = 1; - } + if (__afl_sharedmem_fuzzing) { __afl_map_shm_fuzz(); } while (1) { @@ -1225,7 +937,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++ tool"); _exit(1); } diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index 1f796e53..a3a869d7 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1030,6 +1030,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, * send any data anymore - except a future option requires this. */ + if ((status & FS_NEW_ERROR) == FS_NEW_ERROR) { + + report_error_and_exit(status & 0x0000ffff); + + } + if (status >= 0x41464c00 && status <= 0x41464cff) { u32 version = status - 0x41464c00; @@ -1047,6 +1053,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, } + u32 keep = status; status ^= 0xffffffff; if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) { @@ -1064,7 +1071,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if (getenv("AFL_DEBUG")) { - ACTF("Forkserver options received: (%08x)", status); + ACTF("Forkserver options received: (0x%08x)", status); } @@ -1178,7 +1185,11 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, u32 status2; rlen = read(fsrv->fsrv_st_fd, &status2, 4); - if (status2 != status) { FATAL("Error in forkserver communication"); } + if (status2 != keep) { + + FATAL("Error in forkserver communication (%08x=>%08x)", keep, status2); + + } } else { -- cgit 1.4.1 From c77709cdd9b50832ed537dfd65d30bc7ffa79e7b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Feb 2024 16:03:12 +0100 Subject: add U256/32byte support --- include/cmplog.h | 19 ++++----- instrumentation/afl-compiler-rt.o.c | 78 +++++++++++++++++++++++++++---------- src/afl-forkserver.c | 10 +++++ src/afl-fuzz-redqueen.c | 10 ++--- src/afl-fuzz.c | 6 ++- test/test-llvm.sh | 2 +- 6 files changed, 87 insertions(+), 38 deletions(-) diff --git a/include/cmplog.h b/include/cmplog.h index 6bfc146b..91c2a665 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -43,13 +43,11 @@ struct cmp_header { - unsigned hits : 24; - unsigned id : 24; - unsigned shape : 5; - unsigned type : 2; - unsigned attribute : 4; - unsigned overflow : 1; - unsigned reserved : 4; + unsigned hits : 6; // up to 63 entries, we have CMP_MAP_H = 32 + unsigned shape : 6; // 63 bytes, we support 32 max + unsigned type : 2; // 4, we use 3: none, rtn, cmp + unsigned attribute : 4; // 16 for arithmetic comparison types + unsigned reserved : 6; } __attribute__((packed)); @@ -59,14 +57,17 @@ struct cmp_operands { u64 v1; u64 v0_128; u64 v1_128; + u64 unused; + u8 unused1; + u8 unused2; } __attribute__((packed)); struct cmpfn_operands { - u8 v0[31]; + u8 v0[32]; u8 v0_len; - u8 v1[31]; + u8 v1[32]; u8 v1_len; } __attribute__((packed)); diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index c342334c..a154bcf7 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -186,6 +186,8 @@ __thread u32 __afl_prev_ctx; struct cmp_map *__afl_cmp_map; struct cmp_map *__afl_cmp_map_backup; +static u8 __afl_cmplog_max_len = 16; + /* Child pid? */ static s32 child_pid; @@ -730,6 +732,12 @@ static void __afl_map_shm(void) { #endif // __AFL_CODE_COVERAGE + if (!__afl_cmp_map && getenv("AFL_CMPLOG_DEBUG")) { + + __afl_cmp_map_backup = __afl_cmp_map = malloc(sizeof(struct cmp_map)); + + } + } /* unmap SHM. */ @@ -1893,7 +1901,8 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) { void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) { - if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; + if (likely(!__afl_cmp_map)) return; + if (unlikely(arg1 == arg2)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -1931,7 +1940,8 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) { // fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr); - if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; + if (likely(!__afl_cmp_map)) return; + if (unlikely(arg1 == arg2)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -1969,7 +1979,8 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) { // fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr); - if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; + if (likely(!__afl_cmp_map)) return; + if (unlikely(arg1 == arg2)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -2012,7 +2023,8 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr, // (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1, // attr); - if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; + if (likely(!__afl_cmp_map)) return; + if (unlikely(arg1 == arg2 || size > __afl_cmplog_max_len)) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -2056,6 +2068,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 (likely(!__afl_cmp_map)) return; + if (16 > __afl_cmplog_max_len) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -2249,13 +2262,25 @@ void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len) { // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len); if (likely(!__afl_cmp_map)) return; - if (unlikely(!len)) return; - int len0 = MIN(len, 31); + if (unlikely(!len || len > __afl_cmplog_max_len)) return; + + int len0 = MIN(len, 32); + int len1 = strnlen(ptr1, len0); - if (len1 < 31) len1 = area_is_valid(ptr1, len1 + 1); + if (len1 <= 32) len1 = area_is_valid(ptr1, len1 + 1); + if (len1 > __afl_cmplog_max_len) len1 = 0; + int len2 = strnlen(ptr2, len0); - if (len2 < 31) len2 = area_is_valid(ptr2, len2 + 1); - int l = MAX(len1, len2); + if (len2 <= 32) len2 = area_is_valid(ptr2, len2 + 1); + if (len2 > __afl_cmplog_max_len) len2 = 0; + + int l; + if (!len1) + l = len2; + else if (!len2) + l = len1; + else + l = MAX(len1, len2); if (l < 2) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); @@ -2299,10 +2324,18 @@ void __cmplog_rtn_hook_str(u8 *ptr1, u8 *ptr2) { // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); if (likely(!__afl_cmp_map)) return; if (unlikely(!ptr1 || !ptr2)) return; - int len1 = strnlen(ptr1, 30) + 1; - int len2 = strnlen(ptr2, 30) + 1; - int l = MAX(len1, len2); - if (l < 3) return; + int len1 = strnlen(ptr1, 31) + 1; + int len2 = strnlen(ptr2, 31) + 1; + if (len1 > __afl_cmplog_max_len) len1 = 0; + if (len2 > __afl_cmplog_max_len) len2 = 0; + int l; + if (!len1) + l = len2; + else if (!len2) + l = len1; + else + l = MAX(len1, len2); + if (l < 2) return; uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); @@ -2344,7 +2377,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { /* u32 i; - if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return; + if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return; fprintf(stderr, "rtn arg0="); for (i = 0; i < 32; i++) fprintf(stderr, "%02x", ptr1[i]); @@ -2357,10 +2390,10 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) { // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); if (likely(!__afl_cmp_map)) return; int l1, l2; - if ((l1 = area_is_valid(ptr1, 31)) <= 0 || - (l2 = area_is_valid(ptr2, 31)) <= 0) + if ((l1 = area_is_valid(ptr1, 32)) <= 0 || + (l2 = area_is_valid(ptr2, 32)) <= 0) return; - int len = MIN(31, MIN(l1, l2)); + int len = MIN(__afl_cmplog_max_len, MIN(l1, l2)); // fprintf(stderr, "RTN2 %u\n", len); uintptr_t k = (uintptr_t)__builtin_return_address(0); @@ -2409,7 +2442,7 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) { #if 0 /* u32 i; - if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return; + if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return; fprintf(stderr, "rtn_n len=%u arg0=", len); for (i = 0; i < len; i++) fprintf(stderr, "%02x", ptr1[i]); @@ -2421,12 +2454,15 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) { // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len); if (likely(!__afl_cmp_map)) return; - if (unlikely(!len)) return; - int l = MIN(31, len); + if (!len) return; + int l = MIN(32, len), l1, l2; - if ((l = area_is_valid(ptr1, l)) <= 0 || (l = area_is_valid(ptr2, l)) <= 0) + if ((l1 = area_is_valid(ptr1, l)) <= 0 || (l2 = area_is_valid(ptr2, l)) <= 0) return; + len = MIN(l1, l2); + if (len > __afl_cmplog_max_len) return; + // fprintf(stderr, "RTN2 %u\n", l); uintptr_t k = (uintptr_t)__builtin_return_address(0); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index a3a869d7..c5184639 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -1105,6 +1105,10 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, fsrv->map_size = tmp_map_size; + } else { + + fsrv->real_map_size = fsrv->map_size = MAP_SIZE; + } if ((status & FS_NEW_OPT_SHDMEM_FUZZ)) { @@ -1208,6 +1212,12 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, if ((status & FS_OPT_ERROR) == FS_OPT_ERROR) report_error_and_exit(FS_OPT_GET_ERROR(status)); + if (fsrv->cmplog_binary) { + + FATAL("Target was recompiled with outdated CMPLOG, recompile it!\n"); + + } + if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) { // workaround for recent AFL++ versions diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index eead7a8b..eb96de68 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -11,7 +11,7 @@ Andrea Fioraldi Copyright 2016, 2017 Google Inc. All rights reserved. - Copyright 2019-2024 AFLplusplus Project. All rights reserved. + Copyright 2019-2023 AFLplusplus Project. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -2219,15 +2219,15 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 || - ol0 > 31 || ol1 > 31) { + if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 32 || l1 > 32 || + ol0 > 32 || ol1 > 32) { l0 = ol0 = hshape; } u8 lmax = MAX(l0, ol0); - u8 save[40]; + u8 save[80]; u32 saved_idx = idx, pre, from = 0, to = 0, i, j; u32 its_len = MIN(MIN(lmax, hshape), len - idx); its_len = MIN(its_len, taint_len); @@ -2330,7 +2330,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, u32 tob64 = 0, fromb64 = 0; u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; - u8 xor_val[32], arith_val[32], tmp[48]; + u8 xor_val[64], arith_val[64], tmp[64]; idx = saved_idx; its_len = saved_its_len; diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index b556b4b6..34268113 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -956,9 +956,11 @@ int main(int argc, char **argv_orig, char **envp) { break; case 'd': - case 'D': /* old deterministic */ + case 'D': /* old deterministic */ - WARNF("Parameters -d and -D are deprecated, a new enhanced deterministic fuzzing is active by default, to disable it use -z"); + WARNF( + "Parameters -d and -D are deprecated, a new enhanced deterministic " + "fuzzing is active by default, to disable it use -z"); break; case 'z': /* no deterministic */ diff --git a/test/test-llvm.sh b/test/test-llvm.sh index 53bbd7b4..aef7a5e2 100755 --- a/test/test-llvm.sh +++ b/test/test-llvm.sh @@ -62,7 +62,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && { $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed" CODE=1 } - rm -f test-instr.ts.0 test-instr.ts.1 + rm -f test-instr.ts.0 test-instr.ts.1 test-instr.ts } || { $ECHO "$RED[!] llvm_mode (threadsafe) failed" CODE=1 -- cgit 1.4.1 From 34a3060b0fee900331decce0bae55d4caefafc01 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Feb 2024 16:08:57 +0100 Subject: config __afl_cmplog_max_len --- include/envs.h | 2 +- instrumentation/afl-compiler-rt.o.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/envs.h b/include/envs.h index 0f645d23..8f342553 100644 --- a/include/envs.h +++ b/include/envs.h @@ -21,7 +21,7 @@ static char *afl_environment_variables[] = { "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW", "AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME", - "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE", + "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE", "AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM", "AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT", diff --git a/instrumentation/afl-compiler-rt.o.c b/instrumentation/afl-compiler-rt.o.c index a154bcf7..c4177b08 100644 --- a/instrumentation/afl-compiler-rt.o.c +++ b/instrumentation/afl-compiler-rt.o.c @@ -186,7 +186,7 @@ __thread u32 __afl_prev_ctx; struct cmp_map *__afl_cmp_map; struct cmp_map *__afl_cmp_map_backup; -static u8 __afl_cmplog_max_len = 16; +static u8 __afl_cmplog_max_len = 32; // 16-32 /* Child pid? */ @@ -738,6 +738,13 @@ static void __afl_map_shm(void) { } + if (getenv("AFL_CMPLOG_MAX_LEN")) { + + int tmp = atoi(getenv("AFL_CMPLOG_MAX_LEN")); + if (tmp >= 16 && tmp <= 32) { __afl_cmplog_max_len = tmp; } + + } + } /* unmap SHM. */ -- cgit 1.4.1 From 6d209ce045c651089e4e55d7bb9995b496a378c0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Feb 2024 16:16:32 +0100 Subject: fix -z --- src/afl-fuzz-stats.c | 2 +- src/afl-fuzz.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/afl-fuzz-stats.c b/src/afl-fuzz-stats.c index 76577081..b6900506 100644 --- a/src/afl-fuzz-stats.c +++ b/src/afl-fuzz-stats.c @@ -1112,7 +1112,7 @@ void show_stats_normal(afl_state_t *afl) { } else if (likely(afl->skip_deterministic)) { - strcpy(tmp, "disabled (default, enable with -D)"); + strcpy(tmp, "disabled (-z switch used)"); } else { diff --git a/src/afl-fuzz.c b/src/afl-fuzz.c index 34268113..abb1d82a 100644 --- a/src/afl-fuzz.c +++ b/src/afl-fuzz.c @@ -539,7 +539,7 @@ int main(int argc, char **argv_orig, char **envp) { // still available: HjJkKqruvwz while ((opt = getopt(argc, argv, "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:" - "T:UV:WXx:YZ")) > 0) { + "T:UV:WXx:YzZ")) > 0) { switch (opt) { -- cgit 1.4.1 From 47e7d243f7522b21beeb7bb9e91f3f312a9659f0 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 4 Feb 2024 16:18:21 +0100 Subject: increase version --- README.md | 2 +- include/config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f713e971..f15089c2 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Release version: [4.10c](https://github.com/AFLplusplus/AFLplusplus/releases) -GitHub version: 4.10c +GitHub version: 4.20a Repository: [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) diff --git a/include/config.h b/include/config.h index 9349828f..f3392431 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 "++4.10c" +#define VERSION "++4.20a" /****************************************************** * * -- cgit 1.4.1 From 40df85d1e6fb80e9d641064e645a48b623aee681 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 5 Feb 2024 15:05:46 +0100 Subject: adjust cmplog header --- .github/workflows/ci.yml | 1 + GNUmakefile | 4 +- include/cmplog.h | 10 ++-- src/afl-fuzz-redqueen.c | 43 ++++++++++++-- src/hashmap.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+), 13 deletions(-) create mode 100644 src/hashmap.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ed382fbb..dd0d13e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - stable - dev + - 420 pull_request: branches: - dev # No need for stable-pull-request, as that equals dev-push diff --git a/GNUmakefile b/GNUmakefile index 283c57c2..d3cf2674 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -464,8 +464,8 @@ src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h $(CC) $(CFLAGS) $(CFLAGS_FLTO) -c src/afl-sharedmem.c -o src/afl-sharedmem.o -afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86 - $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm +afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c | test_x86 + $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) -Wno-shift-count-overflow $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c -o $@ $(PYFLAGS) $(LDFLAGS) -lm afl-showmap: src/afl-showmap.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-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) diff --git a/include/cmplog.h b/include/cmplog.h index 91c2a665..589570fe 100644 --- a/include/cmplog.h +++ b/include/cmplog.h @@ -38,16 +38,16 @@ #define SHAPE_BYTES(x) (x + 1) -#define CMP_TYPE_INS 1 -#define CMP_TYPE_RTN 2 +#define CMP_TYPE_INS 0 +#define CMP_TYPE_RTN 1 struct cmp_header { unsigned hits : 6; // up to 63 entries, we have CMP_MAP_H = 32 - unsigned shape : 6; // 63 bytes, we support 32 max - unsigned type : 2; // 4, we use 3: none, rtn, cmp + unsigned shape : 5; // 31+1 bytes + unsigned type : 1; // 4, we use 3: none, rtn, cmp unsigned attribute : 4; // 16 for arithmetic comparison types - unsigned reserved : 6; + //unsigned reserved : 6; } __attribute__((packed)); diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index eb96de68..bc83c9ed 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -87,6 +87,11 @@ static u32 hshape; static u64 screen_update; static u64 last_update; +// hashmap functions +void hashmap_reset(); +bool hashmap_search_and_add(uint8_t type, uint64_t key); +bool hashmap_search_and_add_ptr(uint8_t type, u8 *key); + static struct range *add_range(struct range *ranges, u32 start, u32 end) { struct range *r = ck_alloc_nozero(sizeof(struct range)); @@ -795,7 +800,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, u64 *o_buf_64 = (u64 *)&orig_buf[idx]; u32 *o_buf_32 = (u32 *)&orig_buf[idx]; u16 *o_buf_16 = (u16 *)&orig_buf[idx]; - u8 *o_buf_8 = &orig_buf[idx]; + // u8 *o_buf_8 = &orig_buf[idx]; u32 its_len = MIN(len - idx, taint_len); @@ -836,6 +841,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, // necessary for preventing heap access overflow bytes = MIN(bytes, len - idx); + if (unlikely(bytes <= 1)) { return 0; } // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 if (afl->cmplog_enable_transform && (lvl & LVL3)) { @@ -1266,6 +1272,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } + /* if (*status != 1) { // u8 // if (its_len >= 1) @@ -1290,6 +1297,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h, } + */ + } // If 'S' is set for cmplog mode then we try a scale encoding of the value. @@ -1881,6 +1890,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, hshape = SHAPE_BYTES(h->shape); + if (hshape < 2) { return 0; } + if (h->hits > CMP_MAP_H) { loggeds = CMP_MAP_H; @@ -1906,8 +1917,6 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, #endif - if (hshape < 2) { return 0; } - for (i = 0; i < loggeds; ++i) { struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; @@ -1945,6 +1954,16 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, } + // TODO: add attribute? not sure + if (hshape <= 8 && !hashmap_search_and_add(hshape - 1, o->v0) && + !hashmap_search_and_add(hshape - 1, orig_o->v0) && + !hashmap_search_and_add(hshape - 1, o->v1) && + !hashmap_search_and_add(hshape - 1, orig_o->v1)) { + + continue; + + } + #ifdef _DEBUG fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n", orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape); @@ -2615,12 +2634,13 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry, } - memcpy(buf + idx, tmp, hlen + 1 + off); + u32 tmp_l = hlen + 1 + off; + memcpy(buf + idx, tmp, tmp_l); if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } - tmp[hlen + 1 + off] = 0; + tmp[tmp_l] = 0; // fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result // %u\n", idx, len, fromhex, tmp, repl, *status); - memcpy(buf + idx, save, hlen + 1 + off); + memcpy(buf + idx, save, tmp_l); } @@ -2755,6 +2775,15 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, fprintf(stderr, "\n"); #endif + if (hshape <= 8 && !hashmap_search_and_add_ptr(hshape - 1, o->v0) && + !hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) && + !hashmap_search_and_add_ptr(hshape - 1, o->v1) && + !hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) { + + continue; + + } + t = taint; while (t->next) { @@ -3021,6 +3050,8 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) { // Start insertion loop + hashmap_reset(); + u64 orig_hit_cnt, new_hit_cnt; u64 orig_execs = afl->fsrv.total_execs; orig_hit_cnt = afl->queued_items + afl->saved_crashes; diff --git a/src/hashmap.c b/src/hashmap.c new file mode 100644 index 00000000..a0a9283c --- /dev/null +++ b/src/hashmap.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include +#include "types.h" +#define TABLE_SIZE 10007 // Use a prime number for better distribution + +typedef struct HashNode { + + uint64_t key; + struct HashNode *next; + +} HashNode; + +typedef struct HashMap { + + HashNode **table; + +} HashMap; + +static HashMap *_hashmap; + +void hashmap_reset() { + + if (unlikely(!_hashmap)) { + + _hashmap = (HashMap *)malloc(sizeof(HashMap)); + _hashmap->table = (HashNode **)malloc(sizeof(HashNode *) * TABLE_SIZE); + memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE); + + } else { + + for (int i = 0; i < TABLE_SIZE; i++) { + + HashNode *node = _hashmap->table[i]; + while (node) { + + HashNode *temp = node; + node = node->next; + free(temp); + + } + + } + + memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE); + + } + +} + +static inline unsigned int hash(uint64_t key) { + + return key % TABLE_SIZE; + +} + +// type must be below 8 +bool hashmap_search_and_add(uint8_t type, uint64_t key) { + + if (unlikely(type >= 8)) return false; + uint64_t val = (key & 0xf8ffffffffffffff) + (type << 56); + unsigned int index = hash(val); + HashNode *node = _hashmap->table[index]; + while (node) { + + if (node->key == val) return true; + node = node->next; + + } + + // not found so add it + node = (HashNode *)malloc(sizeof(HashNode)); + node->key = val; + node->next = _hashmap->table[index]; + _hashmap->table[index] = node; + + return false; + +} + +// type must be below 8 +bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) { + + if (unlikely(type >= 8)) return false; + uint64_t key_t = 0; + memcpy(((char *)key_t) + (7 - type), key, type + 1); + return hashmap_search_and_add(type, key_t); + +} + +/* below is not used */ + +void hashmap_insert(uint64_t key) { + + unsigned int index = hash(key); + HashNode *node = (HashNode *)malloc(sizeof(HashNode)); + node->key = key; + node->next = _hashmap->table[index]; + _hashmap->table[index] = node; + +} + +bool hashmap_search(uint64_t key) { + + unsigned int index = hash(key); + HashNode *node = _hashmap->table[index]; + while (node) { + + if (node->key == key) return true; + node = node->next; + + } + + return false; + +} + +void delete(uint64_t key) { + + unsigned int index = hash(key); + HashNode *prev = NULL, *node = _hashmap->table[index]; + while (node) { + + if (node->key == key) { + + if (prev) + prev->next = node->next; + else + _hashmap->table[index] = node->next; + free(node); + return; + + } + + prev = node; + node = node->next; + + } + +} + +void freeHashMap(HashMap *map) { + + free(_hashmap->table); + free(map); + +} + -- cgit 1.4.1 From 698f1e272b8738cd1145ed687861fa5664f14c9b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 Feb 2024 09:34:21 +0100 Subject: fix hashmap test --- src/afl-fuzz-redqueen.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/afl-fuzz-redqueen.c b/src/afl-fuzz-redqueen.c index bc83c9ed..03a25903 100644 --- a/src/afl-fuzz-redqueen.c +++ b/src/afl-fuzz-redqueen.c @@ -1955,10 +1955,10 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, } // TODO: add attribute? not sure - if (hshape <= 8 && !hashmap_search_and_add(hshape - 1, o->v0) && - !hashmap_search_and_add(hshape - 1, orig_o->v0) && - !hashmap_search_and_add(hshape - 1, o->v1) && - !hashmap_search_and_add(hshape - 1, orig_o->v1)) { + if (hshape <= 8 && hashmap_search_and_add(hshape - 1, o->v0) && + hashmap_search_and_add(hshape - 1, orig_o->v0) && + hashmap_search_and_add(hshape - 1, o->v1) && + hashmap_search_and_add(hshape - 1, orig_o->v1)) { continue; @@ -2775,10 +2775,10 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf, fprintf(stderr, "\n"); #endif - if (hshape <= 8 && !hashmap_search_and_add_ptr(hshape - 1, o->v0) && - !hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) && - !hashmap_search_and_add_ptr(hshape - 1, o->v1) && - !hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) { + if (hshape <= 8 && hashmap_search_and_add_ptr(hshape - 1, o->v0) && + hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) && + hashmap_search_and_add_ptr(hshape - 1, o->v1) && + hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) { continue; -- cgit 1.4.1