From 0a9916deab1b96a5a8cea352836f899064a8c2ff Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 May 2025 14:16:50 +0200 Subject: [PATCH 01/20] instrument hidden selects --- .../SanitizerCoveragePCGUARD.so.cc | 111 +++++++++++++++++- 1 file changed, 106 insertions(+), 5 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 670f06c1..126f9ed5 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -206,7 +206,7 @@ class ModuleSanitizerCoverageAFL SanitizerCoverageOptions Options; - uint32_t instr = 0, selects = 0, unhandled = 0, dump_cc = 0; + uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, dump_cc = 0; GlobalVariable *AFLMapPtr = NULL; ConstantInt *One = NULL; ConstantInt *Zero = NULL; @@ -506,8 +506,8 @@ bool ModuleSanitizerCoverageAFL::instrumentModule( getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %u locations with no collisions (%s mode) of which are " - "%u handled and %u unhandled selects.", - instr, modeline, selects, unhandled); + "%u handled, %u hidden and %u unhandled selects.", + instr, modeline, selects, hidden, unhandled); } @@ -781,7 +781,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (AllBlocks.empty()) return false; - uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0; + uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0, + cnt_hidden_sel_inc = 0; static uint32_t first = 1; for (auto &BB : F) { @@ -827,6 +828,39 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( cnt_sel++; cnt_sel_inc += 2; + Value *trueVal = selectInst->getTrueValue(); + Value *falseVal = selectInst->getFalseValue(); + BasicBlock *bb = selectInst->getParent(); + + auto isFromICmpInSameBB = [bb](Value *v) -> bool { + + if (Instruction *inst = dyn_cast(v)) { + + return isa(inst) && inst->getParent() == bb; + + } + + return false; + + }; + + if (isFromICmpInSameBB(trueVal)) { + + cnt_hidden_sel++; + cnt_hidden_sel_inc += 2; + // fprintf(stderr, "trueval '%s'!\n", + // trueVal->getName().str().c_str()); + + } + + if (isFromICmpInSameBB(falseVal)) { + + cnt_hidden_sel++; + cnt_hidden_sel_inc += 2; + // fprintf(stderr, "falseval!\n"); + + } + } else if (t->getTypeID() == llvm::Type::FixedVectorTyID) { @@ -847,10 +881,12 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - CreateFunctionLocalArrays(F, AllBlocks, first + cnt_cov + cnt_sel_inc); + CreateFunctionLocalArrays(F, AllBlocks, + first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc); if (first) { first = 0; } selects += cnt_sel; + hidden += cnt_hidden_sel; uint32_t special = 0, local_selects = 0, skip_next = 0; @@ -936,6 +972,71 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2); + Value *trueVal = selectInst->getTrueValue(); + Value *falseVal = selectInst->getFalseValue(); + BasicBlock *bb = selectInst->getParent(); + + auto isFromICmpInSameBB = [bb](Value *v) -> bool { + + if (Instruction *inst = dyn_cast(v)) { + + return isa(inst) && inst->getParent() == bb; + + } + + return false; + + }; + + if (isFromICmpInSameBB(trueVal)) { + + // fprintf(stderr, "trueval2 '%s'!\n", + // trueVal->getName().str().c_str()); + + auto GuardPtr1 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); + + auto GuardPtr2 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); + + result = IRB.CreateSelect(trueVal, GuardPtr1, GuardPtr2); + + } + + if (isFromICmpInSameBB(falseVal)) { + + auto GuardPtr1 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); + + auto GuardPtr2 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); + + result = IRB.CreateSelect(falseVal, GuardPtr1, GuardPtr2); + + // fprintf(stderr, "falseval2!\n"); } + + } + } else #if LLVM_VERSION_MAJOR >= 14 From 5bf01afd6b2dff1b4e7efacfd59b050a1ce72a81 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 May 2025 14:40:08 +0200 Subject: [PATCH 02/20] fix --- instrumentation/SanitizerCoveragePCGUARD.so.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 126f9ed5..a13ce5d3 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -935,7 +935,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( SelectInst *selectInst = nullptr; - if (!skip_next && (selectInst = dyn_cast(&IN))) { + if (skip_next) { + + skip_next--; + + } else if ((selectInst = dyn_cast(&IN))) { uint32_t vector_cnt = 0; Value *condition = selectInst->getCondition(); @@ -1010,6 +1014,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( Int32PtrTy); result = IRB.CreateSelect(trueVal, GuardPtr1, GuardPtr2); + skip_next++; } @@ -1032,6 +1037,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( Int32PtrTy); result = IRB.CreateSelect(falseVal, GuardPtr1, GuardPtr2); + skip_next++; // fprintf(stderr, "falseval2!\n"); } @@ -1195,7 +1201,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - skip_next = 1; + skip_next++; instr += vector_cnt; } else { From fcca917f4f358ba67887720a2175d3be26f8db71 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Tue, 6 May 2025 17:22:10 +0200 Subject: [PATCH 03/20] better variable following --- .../SanitizerCoveragePCGUARD.so.cc | 116 +++++++++++++++--- 1 file changed, 98 insertions(+), 18 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index a13ce5d3..93ced92e 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -819,6 +819,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( SelectInst *selectInst = nullptr; + // errs() << "IN: " << *(&IN) << "\n"; + if ((selectInst = dyn_cast(&IN))) { Value *c = selectInst->getCondition(); @@ -834,13 +836,54 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( auto isFromICmpInSameBB = [bb](Value *v) -> bool { - if (Instruction *inst = dyn_cast(v)) { + std::function traceBack = [&](Value *val) -> bool { - return isa(inst) && inst->getParent() == bb; + if (auto *inst = dyn_cast(val)) { - } + if (inst->getParent() != bb) return false; - return false; + if (isa(inst)) { + + // errs() << "FOUND: " << *inst << "\n"; + return true; + + } + + if (isa(inst) || inst == &bb->front()) return false; + + // If operands are all constants or loads, stop + bool allTerminating = true; + for (Use &U : inst->operands()) { + + if (!isa(U) && !isa(U)) { + + allTerminating = false; + break; + + } + + } + + if (allTerminating) return false; + + // Recurse on variable operands + for (Use &U : inst->operands()) { + + if (!isa(U) && !isa(U)) { + + if (traceBack(U.get())) return true; + + } + + } + + } + + return false; + + }; + + return traceBack(v); }; @@ -848,18 +891,24 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( cnt_hidden_sel++; cnt_hidden_sel_inc += 2; - // fprintf(stderr, "trueval '%s'!\n", - // trueVal->getName().str().c_str()); + // errs() << "TRUEVAL: " << *selectInst << " |>| " << *c << " | " + // << *trueVal << " | " << *falseVal << "\n"; - } + } // else + + // errs() << "truenot: " << *trueVal << "\n"; if (isFromICmpInSameBB(falseVal)) { cnt_hidden_sel++; cnt_hidden_sel_inc += 2; - // fprintf(stderr, "falseval!\n"); - } + // errs() << "FALSEVAL: " << *selectInst << " |>| " << *c << " | " + // << *trueVal << " | " << *falseVal << "\n"; + + } // else + + // errs() << "falsenot: " << *falseVal << "\n"; } @@ -982,21 +1031,54 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( auto isFromICmpInSameBB = [bb](Value *v) -> bool { - if (Instruction *inst = dyn_cast(v)) { + std::function traceBack = [&](Value *val) -> bool { - return isa(inst) && inst->getParent() == bb; + if (auto *inst = dyn_cast(val)) { - } + if (inst->getParent() != bb) return false; - return false; + if (isa(inst)) return true; + + if (isa(inst) || inst == &bb->front()) return false; + + // If operands are all constants or loads, stop + bool allTerminating = true; + for (Use &U : inst->operands()) { + + if (!isa(U) && !isa(U)) { + + allTerminating = false; + break; + + } + + } + + if (allTerminating) return false; + + // Recurse on variable operands + for (Use &U : inst->operands()) { + + if (!isa(U) && !isa(U)) { + + if (traceBack(U.get())) return true; + + } + + } + + } + + return false; + + }; + + return traceBack(v); }; if (isFromICmpInSameBB(trueVal)) { - // fprintf(stderr, "trueval2 '%s'!\n", - // trueVal->getName().str().c_str()); - auto GuardPtr1 = IRB.CreateIntToPtr( IRB.CreateAdd( IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), @@ -1039,8 +1121,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( result = IRB.CreateSelect(falseVal, GuardPtr1, GuardPtr2); skip_next++; - // fprintf(stderr, "falseval2!\n"); } - } } else From 22b7d370bc36c030d8a8bae4efee3659d07befa6 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Wed, 7 May 2025 19:01:51 +0200 Subject: [PATCH 04/20] try different intrumentation strategy --- .../SanitizerCoveragePCGUARD.so.cc | 523 ++++++++++-------- 1 file changed, 281 insertions(+), 242 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 93ced92e..b76ec5c9 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -782,11 +782,13 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (AllBlocks.empty()) return false; uint32_t cnt_cov = 0, cnt_sel = 0, cnt_sel_inc = 0, cnt_hidden_sel = 0, - cnt_hidden_sel_inc = 0; + cnt_hidden_sel_inc = 0, skip_blocks = 0; static uint32_t first = 1; for (auto &BB : F) { + bool block_is_instrumented = false; + for (auto &IN : BB) { CallInst *callInst = nullptr; @@ -800,11 +802,11 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (!FuncName.compare(StringRef("dlopen")) || !FuncName.compare(StringRef("_dlopen"))) { - fprintf(stderr, - "WARNING: dlopen() detected. To have coverage for a library " - "that your target dlopen()'s this must either happen before " - "__AFL_INIT() or you must use AFL_PRELOAD to preload all " - "dlopen()'ed libraries!\n"); + WARNF( + "dlopen() detected. To have coverage for a library that your " + "target dlopen()'s this must either happen before __AFL_INIT() " + "or you must use AFL_PRELOAD to preload all dlopen()'ed " + "libraries!\n"); continue; } @@ -812,137 +814,134 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) { cnt_cov++; + block_is_instrumented = true; } } - SelectInst *selectInst = nullptr; + bool instrumentInst = false; - // errs() << "IN: " << *(&IN) << "\n"; + if (isa(&IN) || isa(&IN) || isa(&IN) || + isa(&IN)) { - if ((selectInst = dyn_cast(&IN))) { + bool usedInBranch = false; - Value *c = selectInst->getCondition(); - auto t = c->getType(); - if (t->getTypeID() == llvm::Type::IntegerTyID) { + for (auto *U : IN.users()) { - cnt_sel++; - cnt_sel_inc += 2; + if (isa(U)) { - Value *trueVal = selectInst->getTrueValue(); - Value *falseVal = selectInst->getFalseValue(); - BasicBlock *bb = selectInst->getParent(); + usedInBranch = true; + break; - auto isFromICmpInSameBB = [bb](Value *v) -> bool { - - std::function traceBack = [&](Value *val) -> bool { - - if (auto *inst = dyn_cast(val)) { - - if (inst->getParent() != bb) return false; - - if (isa(inst)) { - - // errs() << "FOUND: " << *inst << "\n"; - return true; - - } - - if (isa(inst) || inst == &bb->front()) return false; - - // If operands are all constants or loads, stop - bool allTerminating = true; - for (Use &U : inst->operands()) { - - if (!isa(U) && !isa(U)) { - - allTerminating = false; - break; - - } - - } - - if (allTerminating) return false; - - // Recurse on variable operands - for (Use &U : inst->operands()) { - - if (!isa(U) && !isa(U)) { - - if (traceBack(U.get())) return true; - - } - - } - - } - - return false; - - }; - - return traceBack(v); - - }; - - if (isFromICmpInSameBB(trueVal)) { - - cnt_hidden_sel++; - cnt_hidden_sel_inc += 2; - // errs() << "TRUEVAL: " << *selectInst << " |>| " << *c << " | " - // << *trueVal << " | " << *falseVal << "\n"; - - } // else - - // errs() << "truenot: " << *trueVal << "\n"; - - if (isFromICmpInSameBB(falseVal)) { - - cnt_hidden_sel++; - cnt_hidden_sel_inc += 2; - - // errs() << "FALSEVAL: " << *selectInst << " |>| " << *c << " | " - // << *trueVal << " | " << *falseVal << "\n"; - - } // else - - // errs() << "falsenot: " << *falseVal << "\n"; + } } - else if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + if (!usedInBranch) { - FixedVectorType *tt = dyn_cast(t); - if (tt) { + // errs() << "Instrument! " << *(&IN) << "\n"; + instrumentInst = true; + + } + + } + + if (instrumentInst) { + + block_is_instrumented = true; + SelectInst *selectInst; + PHINode *phiInst; + // errs() << "IN: " << *(&IN) << "\n"; + + if ((phiInst = dyn_cast(&IN))) { + + cnt_hidden_sel++; + cnt_hidden_sel_inc += phiInst->getNumIncomingValues(); + + } else if ((selectInst = dyn_cast(&IN))) { + + Value *c = selectInst->getCondition(); + auto t = c->getType(); + if (t->getTypeID() == llvm::Type::IntegerTyID) { cnt_sel++; - cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2); + cnt_sel_inc += 2; + + } else if (t->getTypeID() == llvm::Type::FixedVectorTyID) { + + FixedVectorType *tt = dyn_cast(t); + if (tt) { + + cnt_sel++; + cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2); + + } + + } else { + + if (!be_quiet) { + + WARNF("unknown select ID type: %u\n", t->getTypeID()); + + } } + } else { + + cnt_hidden_sel++; + cnt_hidden_sel_inc += 2; + } } } + if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock()) { + + Instruction *instr = &*BB.begin(); + LLVMContext &Ctx = BB.getContext(); + MDNode *md = MDNode::get(Ctx, MDString::get(Ctx, "skipinstrument")); + instr->setMetadata("tag", md); + skip_blocks++; + + } + } - CreateFunctionLocalArrays(F, AllBlocks, - first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc); + uint32_t xtra = 0; + if (skip_blocks < first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc) { + + xtra = first + cnt_cov + cnt_sel_inc + cnt_hidden_sel_inc - skip_blocks; + + } + + CreateFunctionLocalArrays(F, AllBlocks, xtra); + + if (!FunctionGuardArray) { + + WARNF( + "SANCOV: FunctionGuardArray is NULL, failed to emit instrumentation."); + return false; + + } if (first) { first = 0; } selects += cnt_sel; hidden += cnt_hidden_sel; - uint32_t special = 0, local_selects = 0, skip_next = 0; + uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0, + skip_phi = 0; for (auto &BB : F) { + // errs() << *(&BB) << "\n"; + for (auto &IN : BB) { + // errs() << *(&IN) << "\n"; CallInst *callInst = nullptr; if ((callInst = dyn_cast(&IN))) { @@ -960,15 +959,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( IRBuilder<> IRB(callInst); #endif - if (!FunctionGuardArray) { - - fprintf(stderr, - "SANCOV: FunctionGuardArray is NULL, failed to emit " - "instrumentation."); - continue; - - } - Value *GuardPtr = IRB.CreateIntToPtr( IRB.CreateAdd( IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), @@ -982,31 +972,53 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - SelectInst *selectInst = nullptr; + bool instrumentInst = false; - if (skip_next) { + if (isa(&IN) || isa(&IN) || isa(&IN) || + isa(&IN)) { - skip_next--; + bool usedInBranch = false; - } else if ((selectInst = dyn_cast(&IN))) { + for (auto *U : IN.users()) { + if (isa(U)) { + + usedInBranch = true; + break; + + } + + } + + if (!usedInBranch) { + + // errs() << "Instrument! " << *(&IN) << "\n"; + instrumentInst = true; + + } + + } + + if (instrumentInst) { + + Value *result = nullptr; uint32_t vector_cnt = 0; - Value *condition = selectInst->getCondition(); - Value *result; - auto t = condition->getType(); - IRBuilder<> IRB(selectInst->getNextNode()); + SelectInst *selectInst; + ICmpInst *icmp; + FCmpInst *fcmp; + PHINode *phi = nullptr, *newPhi = nullptr; + IRBuilder<> IRB(IN.getNextNode()); - if (t->getTypeID() == llvm::Type::IntegerTyID) { + if ((icmp = dyn_cast(&IN))) { - if (!FunctionGuardArray) { + if (skip_icmp) { - fprintf(stderr, - "SANCOV: FunctionGuardArray is NULL, failed to emit " - "instrumentation."); + skip_icmp--; continue; } + auto res = icmp; auto GuardPtr1 = IRB.CreateIntToPtr( IRB.CreateAdd( IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), @@ -1023,61 +1035,82 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), Int32PtrTy); - result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2); + result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2); + skip_select = 1; + // fprintf(stderr, "Icmp!\n"); - Value *trueVal = selectInst->getTrueValue(); - Value *falseVal = selectInst->getFalseValue(); - BasicBlock *bb = selectInst->getParent(); + } else if ((fcmp = dyn_cast(&IN))) { - auto isFromICmpInSameBB = [bb](Value *v) -> bool { + auto res = fcmp; + auto GuardPtr1 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); - std::function traceBack = [&](Value *val) -> bool { + auto GuardPtr2 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), + Int32PtrTy); - if (auto *inst = dyn_cast(val)) { + result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2); + skip_select = 1; + // fprintf(stderr, "Fcmp!\n"); - if (inst->getParent() != bb) return false; + } else if ((phi = dyn_cast(&IN))) { - if (isa(inst)) return true; + if (skip_phi) { - if (isa(inst) || inst == &bb->front()) return false; + skip_phi = 0; + // errs() << "SKIP: " << *(&IN) << "\n"; + continue; - // If operands are all constants or loads, stop - bool allTerminating = true; - for (Use &U : inst->operands()) { + } - if (!isa(U) && !isa(U)) { + // errs() << "-->PHI: " << *(&IN) << "\n"; + // continue; + Instruction *insertBefore = &*phi->getParent()->getFirstInsertionPt(); + newPhi = PHINode::Create(Int32PtrTy, 0, "", insertBefore); + BasicBlock *phiBlock = phi->getParent(); - allTerminating = false; - break; + for (BasicBlock *pred : predecessors(phiBlock)) { - } + IRBuilder<> predBuilder(pred->getTerminator()); - } + Value *ptr = predBuilder.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + ConstantInt::get( + IntptrTy, (cnt_cov + local_selects++ + AllBlocks.size()))); + newPhi->addIncoming(ptr, pred); - if (allTerminating) return false; + } - // Recurse on variable operands - for (Use &U : inst->operands()) { + result = newPhi; + skip_phi = 1; + // fprintf(stderr, "Phi!\n"); - if (!isa(U) && !isa(U)) { + } else if ((selectInst = dyn_cast(&IN))) { - if (traceBack(U.get())) return true; + if (skip_select) { - } + skip_select = 0; + continue; - } + } else { - } + // fprintf(stderr, "Select!\n"); - return false; + } - }; + Value *condition = selectInst->getCondition(); + auto t = condition->getType(); - return traceBack(v); - - }; - - if (isFromICmpInSameBB(trueVal)) { + if (t->getTypeID() == llvm::Type::IntegerTyID) { auto GuardPtr1 = IRB.CreateIntToPtr( IRB.CreateAdd( @@ -1095,121 +1128,113 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), Int32PtrTy); - result = IRB.CreateSelect(trueVal, GuardPtr1, GuardPtr2); - skip_next++; + result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2); + skip_select = 1; - } - - if (isFromICmpInSameBB(falseVal)) { - - auto GuardPtr1 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); - - auto GuardPtr2 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); - - result = IRB.CreateSelect(falseVal, GuardPtr1, GuardPtr2); - skip_next++; - - } - - } 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); - uint32_t elements = tt->getElementCount().getFixedValue(); - vector_cnt = elements; - if (elements) { + if (tt) { - FixedVectorType *GuardPtr1 = - FixedVectorType::get(Int32PtrTy, elements); - FixedVectorType *GuardPtr2 = - FixedVectorType::get(Int32PtrTy, elements); - Value *x, *y; + uint32_t elements = tt->getElementCount().getFixedValue(); + vector_cnt = elements; + if (elements) { - if (!FunctionGuardArray) { + FixedVectorType *GuardPtr1 = + FixedVectorType::get(Int32PtrTy, elements); + FixedVectorType *GuardPtr2 = + FixedVectorType::get(Int32PtrTy, elements); + Value *x, *y; - fprintf(stderr, - "SANCOV: FunctionGuardArray is NULL, failed to emit " - "instrumentation."); - continue; - - } - - Value *val1 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); - x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); - - Value *val2 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); - y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); - - for (uint64_t i = 1; i < elements; i++) { - - val1 = IRB.CreateIntToPtr( + Value *val1 = IRB.CreateIntToPtr( IRB.CreateAdd( IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), Int32PtrTy); - x = IRB.CreateInsertElement(x, val1, i); + x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0); - val2 = IRB.CreateIntToPtr( + Value *val2 = IRB.CreateIntToPtr( IRB.CreateAdd( IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), ConstantInt::get(IntptrTy, (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), Int32PtrTy); - y = IRB.CreateInsertElement(y, val2, i); + y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0); + + for (uint64_t i = 1; i < elements; i++) { + + val1 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * + 4)), + Int32PtrTy); + x = IRB.CreateInsertElement(x, val1, i); + + val2 = IRB.CreateIntToPtr( + IRB.CreateAdd( + IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), + ConstantInt::get( + IntptrTy, + (cnt_cov + local_selects++ + AllBlocks.size()) * + 4)), + Int32PtrTy); + y = IRB.CreateInsertElement(y, val2, i); + + } + + result = IRB.CreateSelect(condition, x, y); + skip_select = 1; } - result = IRB.CreateSelect(condition, x, y); - } - } - - } else + } else #endif - { + { - // fprintf(stderr, "UNHANDLED: %u\n", t->getTypeID()); - unhandled++; - continue; + if (!be_quiet) { + + WARNF("Warning: Unhandled ID type: %u\n", t->getTypeID()); + + } + + unhandled++; + continue; + + } } uint32_t vector_cur = 0; /* Load SHM pointer */ + if (newPhi) { + + auto *inst = dyn_cast(result); + PHINode *nphi; + + while ((nphi = dyn_cast(inst))) { + + // fprintf(stderr, "NEXT!\n"); + inst = inst->getNextNode(); + + } + + IRB.SetInsertPoint(inst); + + } LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); @@ -1260,6 +1285,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( auto cf = IRB.CreateICmpEQ(Incr, Zero); auto carry = IRB.CreateZExt(cf, Int8Ty); Incr = IRB.CreateAdd(Incr, carry); + skip_icmp++; } @@ -1281,13 +1307,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - skip_next++; instr += vector_cnt; - } else { - - skip_next = 0; - } } @@ -1296,9 +1317,27 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (AllBlocks.empty() && !special && !local_selects) return false; - if (!AllBlocks.empty()) - for (size_t i = 0, N = AllBlocks.size(); i < N; i++) - InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc); + uint32_t skipped = 0; + + if (!AllBlocks.empty()) { + + for (size_t i = 0, N = AllBlocks.size(); i < N; i++) { + + auto instr = AllBlocks[i]->begin(); + if (instr->getMetadata("skipinstrument")) { + + skipped++; + // fprintf(stderr, "Skipped!\n"); + + } else { + + InjectCoverageAtBlock(F, *AllBlocks[i], i - skipped, IsLeafFunc); + + } + + } + + } return true; From 406e4880c760588d1e349db110a0903af3969229 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 8 May 2025 09:36:05 +0200 Subject: [PATCH 05/20] remove phi instrumentation --- .../SanitizerCoveragePCGUARD.so.cc | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index b76ec5c9..d875aad3 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -822,8 +822,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( bool instrumentInst = false; - if (isa(&IN) || isa(&IN) || isa(&IN) || - isa(&IN)) { + if (isa(&IN) || isa(&IN) || isa(&IN)) { + + // || isa(&IN) bool usedInBranch = false; @@ -851,15 +852,17 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( block_is_instrumented = true; SelectInst *selectInst; - PHINode *phiInst; + // PHINode *phiInst; // errs() << "IN: " << *(&IN) << "\n"; - if ((phiInst = dyn_cast(&IN))) { + /* if ((phiInst = dyn_cast(&IN))) { cnt_hidden_sel++; cnt_hidden_sel_inc += phiInst->getNumIncomingValues(); - } else if ((selectInst = dyn_cast(&IN))) { + } else*/ + + if ((selectInst = dyn_cast(&IN))) { Value *c = selectInst->getCondition(); auto t = c->getType(); @@ -932,8 +935,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( selects += cnt_sel; hidden += cnt_hidden_sel; - uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0, - skip_phi = 0; + uint32_t special = 0, local_selects = 0, skip_select = 0, skip_icmp = 0; + // uint32_t skip_phi = 0; for (auto &BB : F) { @@ -974,8 +977,9 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( bool instrumentInst = false; - if (isa(&IN) || isa(&IN) || isa(&IN) || - isa(&IN)) { + if (isa(&IN) || isa(&IN) || isa(&IN)) { + + // || isa(&IN) bool usedInBranch = false; @@ -1006,7 +1010,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( SelectInst *selectInst; ICmpInst *icmp; FCmpInst *fcmp; - PHINode *phi = nullptr, *newPhi = nullptr; + // PHINode *phi = nullptr, *newPhi = nullptr; IRBuilder<> IRB(IN.getNextNode()); if ((icmp = dyn_cast(&IN))) { @@ -1062,37 +1066,39 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( skip_select = 1; // fprintf(stderr, "Fcmp!\n"); - } else if ((phi = dyn_cast(&IN))) { + /*} else if ((phi = dyn_cast(&IN))) { - if (skip_phi) { + if (skip_phi) { - skip_phi = 0; - // errs() << "SKIP: " << *(&IN) << "\n"; - continue; + skip_phi = 0; + // errs() << "SKIP: " << *(&IN) << "\n"; + continue; - } + } - // errs() << "-->PHI: " << *(&IN) << "\n"; - // continue; - Instruction *insertBefore = &*phi->getParent()->getFirstInsertionPt(); - newPhi = PHINode::Create(Int32PtrTy, 0, "", insertBefore); - BasicBlock *phiBlock = phi->getParent(); + // errs() << "-->PHI: " << *(&IN) << "\n"; + // continue; + Instruction *insertBefore = + &*phi->getParent()->getFirstInsertionPt(); newPhi = + PHINode::Create(Int32PtrTy, 0, "", insertBefore); BasicBlock + *phiBlock = phi->getParent(); - for (BasicBlock *pred : predecessors(phiBlock)) { + for (BasicBlock *pred : predecessors(phiBlock)) { - IRBuilder<> predBuilder(pred->getTerminator()); + IRBuilder<> predBuilder(pred->getTerminator()); - Value *ptr = predBuilder.CreateInBoundsGEP( - FunctionGuardArray->getValueType(), FunctionGuardArray, - ConstantInt::get( - IntptrTy, (cnt_cov + local_selects++ + AllBlocks.size()))); - newPhi->addIncoming(ptr, pred); + Value *ptr = predBuilder.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + ConstantInt::get( + IntptrTy, (cnt_cov + local_selects++ + + AllBlocks.size()))); newPhi->addIncoming(ptr, pred); - } + } - result = newPhi; - skip_phi = 1; - // fprintf(stderr, "Phi!\n"); + result = newPhi; + skip_phi = 1; + // fprintf(stderr, "Phi!\n"); + */ } else if ((selectInst = dyn_cast(&IN))) { @@ -1220,6 +1226,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( uint32_t vector_cur = 0; /* Load SHM pointer */ + /* if (newPhi) { auto *inst = dyn_cast(result); @@ -1236,6 +1243,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + */ + LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); ModuleSanitizerCoverageAFL::SetNoSanitizeMetadata(MapPtr); From 977e08cda1b26b34b6084aba226204b76ddf04bc Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 May 2025 17:07:54 +0200 Subject: [PATCH 06/20] fix fcmp + icmp for vectors --- .../SanitizerCoveragePCGUARD.so.cc | 100 ++++++++++++------ 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index d875aad3..202322f3 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -13,6 +13,7 @@ #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +// #include "llvm/IR/Verifier.h" #if LLVM_VERSION_MAJOR >= 15 #if LLVM_VERSION_MAJOR < 17 #include "llvm/ADT/Triple.h" @@ -506,8 +507,8 @@ bool ModuleSanitizerCoverageAFL::instrumentModule( getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); OKF("Instrumented %u locations with no collisions (%s mode) of which are " - "%u handled, %u hidden and %u unhandled selects.", - instr, modeline, selects, hidden, unhandled); + "%u handled and %u unhandled special instructions.", + instr, modeline, selects + hidden, unhandled); } @@ -852,6 +853,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( block_is_instrumented = true; SelectInst *selectInst; + ICmpInst *icmp; + FCmpInst *fcmp; // PHINode *phiInst; // errs() << "IN: " << *(&IN) << "\n"; @@ -862,7 +865,33 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } else*/ - if ((selectInst = dyn_cast(&IN))) { + if ((icmp = dyn_cast(&IN))) { + + if (icmp->getType()->isIntegerTy(1)) { + + cnt_sel++; + cnt_sel_inc += 2; + + } else { + + unhandled++; + + } + + } else if ((fcmp = dyn_cast(&IN))) { + + if (fcmp->getType()->isIntegerTy(1)) { + + cnt_sel++; + cnt_sel_inc += 2; + + } else { + + unhandled++; + + } + + } else if ((selectInst = dyn_cast(&IN))) { Value *c = selectInst->getCondition(); auto t = c->getType(); @@ -891,12 +920,12 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - } else { + } /*else { cnt_hidden_sel++; cnt_hidden_sel_inc += 2; - } + }*/ } @@ -1015,6 +1044,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if ((icmp = dyn_cast(&IN))) { + if (!icmp->getType()->isIntegerTy(1)) { continue; } + if (skip_icmp) { skip_icmp--; @@ -1023,21 +1054,15 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } auto res = icmp; - auto GuardPtr1 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); + auto GuardPtr1 = IRB.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + {IRB.getInt64(0), + IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))}); - auto GuardPtr2 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); + auto GuardPtr2 = IRB.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + {IRB.getInt64(0), + IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))}); result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2); skip_select = 1; @@ -1045,22 +1070,18 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } else if ((fcmp = dyn_cast(&IN))) { - auto res = fcmp; - auto GuardPtr1 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); + if (!icmp->getType()->isIntegerTy(1)) { continue; } - auto GuardPtr2 = IRB.CreateIntToPtr( - IRB.CreateAdd( - IRB.CreatePointerCast(FunctionGuardArray, IntptrTy), - ConstantInt::get( - IntptrTy, - (cnt_cov + local_selects++ + AllBlocks.size()) * 4)), - Int32PtrTy); + auto res = fcmp; + auto GuardPtr1 = IRB.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + {IRB.getInt64(0), + IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))}); + + auto GuardPtr2 = IRB.CreateInBoundsGEP( + FunctionGuardArray->getValueType(), FunctionGuardArray, + {IRB.getInt64(0), + IRB.getInt32((cnt_cov + local_selects++ + AllBlocks.size()))}); result = IRB.CreateSelect(res, GuardPtr1, GuardPtr2); skip_select = 1; @@ -1348,6 +1369,17 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + /* + if (verifyFunction(F, &errs())) { + + errs() << "Broken function after instrumentation\n"; + F.print(errs(), nullptr); + report_fatal_error("Invalid IR"); + + } + + */ + return true; } From 231a4b1937675b5ab4bf073e67c949a3eaacee9b Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 9 May 2025 17:14:44 +0200 Subject: [PATCH 07/20] fix fcmp --- instrumentation/SanitizerCoveragePCGUARD.so.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 202322f3..ed6de40b 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1070,7 +1070,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } else if ((fcmp = dyn_cast(&IN))) { - if (!icmp->getType()->isIntegerTy(1)) { continue; } + if (!fcmp->getType()->isIntegerTy(1)) { continue; } auto res = fcmp; auto GuardPtr1 = IRB.CreateInBoundsGEP( @@ -1370,13 +1370,13 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } /* - if (verifyFunction(F, &errs())) { + if (verifyFunction(F, &errs())) { - errs() << "Broken function after instrumentation\n"; - F.print(errs(), nullptr); - report_fatal_error("Invalid IR"); + errs() << "Broken function after instrumentation\n"; + F.print(errs(), nullptr); + report_fatal_error("Invalid IR"); - } + } */ From adeaa714ce5d94b59c7cbb97011e7e739f5793d7 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 11 May 2025 19:27:23 +0200 Subject: [PATCH 08/20] do not instrument icmp/fcmp if result is used in select --- .../SanitizerCoveragePCGUARD.so.cc | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index ed6de40b..f8735d0a 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -821,13 +821,16 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - bool instrumentInst = false; + bool instrumentInst = false; + ICmpInst *icmp; + FCmpInst *fcmp; - if (isa(&IN) || isa(&IN) || isa(&IN)) { + if ((icmp = dyn_cast(&IN)) || + (fcmp = dyn_cast(&IN)) || isa(&IN)) { // || isa(&IN) - bool usedInBranch = false; + bool usedInBranch = false, usedInSelectDecision = false; for (auto *U : IN.users()) { @@ -838,9 +841,23 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + if (auto *sel = dyn_cast(U)) { + + if (icmp && sel->getCondition() == icmp) { + + usedInSelectDecision = true; + + } else if (fcmp && sel->getCondition() == fcmp) { + + usedInSelectDecision = true; + + } + + } + } - if (!usedInBranch) { + if (!usedInBranch && !usedInSelectDecision) { // errs() << "Instrument! " << *(&IN) << "\n"; instrumentInst = true; @@ -1004,13 +1021,16 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - bool instrumentInst = false; + bool instrumentInst = false; + ICmpInst *icmp; + FCmpInst *fcmp; - if (isa(&IN) || isa(&IN) || isa(&IN)) { + if ((icmp = dyn_cast(&IN)) || + (fcmp = dyn_cast(&IN)) || isa(&IN)) { // || isa(&IN) - bool usedInBranch = false; + bool usedInBranch = false, usedInSelectDecision = false; for (auto *U : IN.users()) { @@ -1021,9 +1041,23 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + if (auto *sel = dyn_cast(U)) { + + if (icmp && sel->getCondition() == icmp) { + + usedInSelectDecision = true; + + } else if (fcmp && sel->getCondition() == fcmp) { + + usedInSelectDecision = true; + + } + + } + } - if (!usedInBranch) { + if (!usedInBranch && !usedInSelectDecision) { // errs() << "Instrument! " << *(&IN) << "\n"; instrumentInst = true; @@ -1037,8 +1071,6 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( Value *result = nullptr; uint32_t vector_cnt = 0; SelectInst *selectInst; - ICmpInst *icmp; - FCmpInst *fcmp; // PHINode *phi = nullptr, *newPhi = nullptr; IRBuilder<> IRB(IN.getNextNode()); From ea6d182b4a85d9e73662b633fb40f0e7e43934ef Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 11 May 2025 19:52:55 +0200 Subject: [PATCH 09/20] print skipped bb --- .../SanitizerCoveragePCGUARD.so.cc | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index f8735d0a..f9c0fc54 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -77,9 +77,9 @@ #else #include "llvm/Transforms/Utils/Instrumentation.h" #endif - #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/ModuleUtils.h" +#include "llvm/ADT/STLExtras.h" #include "config.h" #include "debug.h" @@ -207,7 +207,8 @@ class ModuleSanitizerCoverageAFL SanitizerCoverageOptions Options; - uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, dump_cc = 0; + uint32_t instr = 0, selects = 0, hidden = 0, unhandled = 0, skippedbb = 0, + dump_cc = 0; GlobalVariable *AFLMapPtr = NULL; ConstantInt *One = NULL; ConstantInt *Zero = NULL; @@ -506,9 +507,16 @@ bool ModuleSanitizerCoverageAFL::instrumentModule( getenv("AFL_USE_TSAN") ? ", TSAN" : "", getenv("AFL_USE_CFISAN") ? ", CFISAN" : "", getenv("AFL_USE_UBSAN") ? ", UBSAN" : ""); + char buf[32] = ""; + if (skippedbb) { + + snprintf(buf, sizeof(buf), " %u instrumentations saved.", skippedbb); + + } + OKF("Instrumented %u locations with no collisions (%s mode) of which are " - "%u handled and %u unhandled special instructions.", - instr, modeline, selects + hidden, unhandled); + "%u handled and %u unhandled special instructions.%s", + instr, modeline, selects + hidden, unhandled, buf); } @@ -948,7 +956,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } - if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock()) { + if (block_is_instrumented && &BB != &BB.getParent()->getEntryBlock() && + llvm::is_contained(AllBlocks, &BB)) { Instruction *instr = &*BB.begin(); LLVMContext &Ctx = BB.getContext(); @@ -1401,6 +1410,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + skippedbb += skipped; + /* if (verifyFunction(F, &errs())) { From b9e361df46a6e9fa407877f2e660fb81f302a804 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 12 May 2025 12:24:52 +0200 Subject: [PATCH 10/20] cmplog: ignore loop icmp --- instrumentation/SanitizerCoverageLTO.so.cc | 4 +-- .../SanitizerCoveragePCGUARD.so.cc | 2 +- instrumentation/afl-llvm-pass.so.cc | 4 +-- instrumentation/cmplog-instructions-pass.cc | 34 +++++++++++++++++-- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index c27ff36a..61f01cab 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -333,7 +333,7 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass { } else { - if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); } + if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); } return false; } @@ -396,7 +396,7 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M, } else { - if (debug) { DEBUGF("Instrument disabled\n"); } + if (debug) { DEBUGF("Instrumentation disabled\n"); } } diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index f9c0fc54..30076953 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -281,7 +281,7 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M, } else { - if (getenv("AFL_DEBUG")) { DEBUGF("Instrument disabled\n"); } + if (getenv("AFL_DEBUG")) { DEBUGF("Instrumentation disabled\n"); } } diff --git a/instrumentation/afl-llvm-pass.so.cc b/instrumentation/afl-llvm-pass.so.cc index 3fb644af..ca133649 100644 --- a/instrumentation/afl-llvm-pass.so.cc +++ b/instrumentation/afl-llvm-pass.so.cc @@ -227,7 +227,7 @@ bool AFLCoverage::runOnModule(Module &M) { #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ if (getenv("AFL_SAN_NO_INST")) { - if (debug) { fprintf(stderr, "Instrument disabled\n"); } + if (debug) { fprintf(stderr, "Instrumentation disabled\n"); } return PreservedAnalyses::all(); } @@ -235,7 +235,7 @@ bool AFLCoverage::runOnModule(Module &M) { #else if (getenv("AFL_SAN_NO_INST")) { - if (debug) { fprintf(stderr, "Instrument disabled\n"); } + if (debug) { fprintf(stderr, "Instrumentation disabled\n"); } return true; } diff --git a/instrumentation/cmplog-instructions-pass.cc b/instrumentation/cmplog-instructions-pass.cc index a2165d7b..3fbe13f2 100644 --- a/instrumentation/cmplog-instructions-pass.cc +++ b/instrumentation/cmplog-instructions-pass.cc @@ -64,6 +64,8 @@ using namespace llvm; namespace { +using DomTreeCallback = function_ref; + #if LLVM_MAJOR >= 11 /* use new pass manager */ class CmpLogInstructions : public PassInfoMixin { @@ -92,6 +94,8 @@ class CmpLogInstructions : public ModulePass { #else bool runOnModule(Module &M) override; + bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT); + #if LLVM_VERSION_MAJOR >= 4 StringRef getPassName() const override { @@ -106,7 +110,7 @@ class CmpLogInstructions : public ModulePass { #endif private: - bool hookInstrs(Module &M); + bool hookInstrs(Module &M, DomTreeCallback DTCallback); }; @@ -158,7 +162,16 @@ Iterator Unique(Iterator first, Iterator last) { } -bool CmpLogInstructions::hookInstrs(Module &M) { +bool IsBackEdge(BasicBlock *From, BasicBlock *To, const DominatorTree *DT) { + + if (DT->dominates(To, From)) return true; + if (auto Next = To->getUniqueSuccessor()) + if (DT->dominates(Next, From)) return true; + return false; + +} + +bool CmpLogInstructions::hookInstrs(Module &M, DomTreeCallback DTCallback) { std::vector icomps; LLVMContext &C = M.getContext(); @@ -296,6 +309,7 @@ bool CmpLogInstructions::hookInstrs(Module &M) { for (auto &F : M) { if (!isInInstrumentList(&F, MNAME)) continue; + const DominatorTree *DT = DTCallback(F); for (auto &BB : F) { @@ -304,6 +318,12 @@ bool CmpLogInstructions::hookInstrs(Module &M) { CmpInst *selectcmpInst = nullptr; if ((selectcmpInst = dyn_cast(&IN))) { + // skip loop comparisons + if (selectcmpInst->hasOneUse()) + if (auto BR = dyn_cast(selectcmpInst->user_back())) + for (BasicBlock *B : BR->successors()) + if (IsBackEdge(BR->getParent(), B, DT)) continue; + icomps.push_back(selectcmpInst); } @@ -681,11 +701,19 @@ bool CmpLogInstructions::runOnModule(Module &M) { #endif + auto &FAM = MAM.getResult(M).getManager(); + auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{ + + return &FAM.getResult(F); + + }; + if (getenv("AFL_QUIET") == NULL) printf("Running cmplog-instructions-pass by andreafioraldi@gmail.com\n"); else be_quiet = 1; - bool ret = hookInstrs(M); + + bool ret = hookInstrs(M, DTCallback); verifyModule(M); #if LLVM_MAJOR >= 11 /* use new pass manager */ From 1631e5988fd63265262520161181e2b38bc1d3eb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sat, 17 May 2025 13:57:24 +0200 Subject: [PATCH 11/20] nit --- instrumentation/SanitizerCoveragePCGUARD.so.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 30076953..d892c22b 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1055,10 +1055,12 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (icmp && sel->getCondition() == icmp) { usedInSelectDecision = true; + break; } else if (fcmp && sel->getCondition() == fcmp) { usedInSelectDecision = true; + break; } From 92d1a60096eded3a02441234f4d09dc670867a84 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Mon, 19 May 2025 10:23:22 +0200 Subject: [PATCH 12/20] print deubg on before missed instrumented instructions --- .../SanitizerCoveragePCGUARD.so.cc | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index 43679e70..6cd770ee 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -1096,6 +1096,26 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( } + if (debug) { + + if (DILocation *Loc = IN.getDebugLoc()) { + + llvm::errs() << "DEBUG " << Loc->getFilename() << ":" + << Loc->getLine() << ":"; + std::string path = + Loc->getDirectory().str() + "/" + Loc->getFilename().str(); + std::ifstream sourceFile(path); + std::string lineContent; + for (unsigned line = 1; line <= Loc->getLine(); ++line) + std::getline(sourceFile, lineContent); + llvm::errs() << lineContent << "\n"; + + } + + errs() << *(&IN) << "\n"; + + } + auto res = icmp; auto GuardPtr1 = IRB.CreateInBoundsGEP( FunctionGuardArray->getValueType(), FunctionGuardArray, @@ -1115,6 +1135,26 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage( if (!fcmp->getType()->isIntegerTy(1)) { continue; } + if (debug) { + + if (DILocation *Loc = IN.getDebugLoc()) { + + llvm::errs() << "DEBUG " << Loc->getFilename() << ":" + << Loc->getLine() << ":"; + std::string path = + Loc->getDirectory().str() + "/" + Loc->getFilename().str(); + std::ifstream sourceFile(path); + std::string lineContent; + for (unsigned line = 1; line <= Loc->getLine(); ++line) + std::getline(sourceFile, lineContent); + llvm::errs() << lineContent << "\n"; + + } + + errs() << *(&IN) << "\n"; + + } + auto res = fcmp; auto GuardPtr1 = IRB.CreateInBoundsGEP( FunctionGuardArray->getValueType(), FunctionGuardArray, From d02390e62e751b940681af5ab50e94a85a4a520f Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Thu, 22 May 2025 17:08:12 +0200 Subject: [PATCH 13/20] add desock option --- docs/fuzzing_in_depth.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/fuzzing_in_depth.md b/docs/fuzzing_in_depth.md index 59a6d4bc..60c2aade 100644 --- a/docs/fuzzing_in_depth.md +++ b/docs/fuzzing_in_depth.md @@ -869,10 +869,11 @@ Here are some of the most important caveats for AFL++: - There is no direct support for fuzzing network services, background daemons, or interactive apps that require UI interaction to work. You may need to make - simple code changes to make them behave in a more traditional way. Preeny or - libdesock may offer a relatively simple option, too - see: + simple code changes to make them behave in a more traditional way. Preeny, + libdesock or desockmulti may offer a relatively simple option, too - see: [https://github.com/zardus/preeny](https://github.com/zardus/preeny) or [https://github.com/fkie-cad/libdesock](https://github.com/fkie-cad/libdesock) + [https://github.com/zyingp/desockmulti](https://github.com/zyingp/desockmulti) Some useful tips for modifying network-based services can be also found at: [https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop](https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop) From cee764689c2855f400ffba7039c12accf12593a6 Mon Sep 17 00:00:00 2001 From: Kuang-che Wu Date: Thu, 22 May 2025 23:10:51 +0800 Subject: [PATCH 14/20] fix save_if_interesting The value of `classified`, `bits_new`, and `cksum`, were not always correctly maintained. 1. In the past, `afl->queue_top->exec_cksum` was always assigned when `add_to_queue`, however it became conditional since cd5764170595. This doesn't change correctness because calibrate_case() will calculate the checksum. However, this mean one calibration run is wasted. 2. Sometimes `classified` is set incorrectly. For example, this code snippet ``` new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); classified = 1; ``` should be changed to ``` new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); if (new_bits) classified = 1; ``` This commit fixed above issues and use macros to make the code easier to understand. This should prevent to forget to set classified in the future (like the bug fixed by 30c93d132166). The macros also defers the calculations to where the values are really needed. This could save cpu if the code returns earlier. For example, if a case is timeout first and not timeout the second time, the current code does classify_counts, which is not always needed. --- include/afl-fuzz.h | 1 - src/afl-fuzz-bitmap.c | 130 +++++++++++++++++++++++------------------- 2 files changed, 70 insertions(+), 61 deletions(-) diff --git a/include/afl-fuzz.h b/include/afl-fuzz.h index c4d2c8f2..c1e6e0c8 100644 --- a/include/afl-fuzz.h +++ b/include/afl-fuzz.h @@ -1216,7 +1216,6 @@ u8 *describe_op(afl_state_t *, u8, size_t); #endif u8 save_if_interesting(afl_state_t *, void *, u32, u8); u8 has_new_bits(afl_state_t *, u8 *); -u8 has_new_bits_unclassified(afl_state_t *, u8 *); #ifndef AFL_SHOWMAP void classify_counts(afl_forkserver_t *); #endif diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 5d3cc71a..5ef1cbf2 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -255,7 +255,8 @@ inline u8 has_new_bits(afl_state_t *afl, u8 *virgin_map) { * on rare cases it fall backs to the slow path: classify_counts() first, then * return has_new_bits(). */ -inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { +static inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map, + bool *classified) { /* Handle the hot path first: no new coverage */ u8 *end = afl->fsrv.trace_bits + afl->fsrv.map_size; @@ -272,6 +273,7 @@ inline u8 has_new_bits_unclassified(afl_state_t *afl, u8 *virgin_map) { #endif /* ^WORD_SIZE_64 */ classify_counts(&afl->fsrv); + *classified = true; return has_new_bits(afl, virgin_map); } @@ -498,13 +500,61 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u8 fn[PATH_MAX]; u8 *queue_fn = ""; - u8 new_bits = 0, keeping = 0, res, is_timeout = 0, need_hash = 1; - u8 classified = 0; + u8 keeping = 0, res, is_timeout = 0; u8 san_fault = 0, san_idx = 0, feed_san = 0; s32 fd; - u64 cksum = 0; u32 cksum_simplified = 0, cksum_unique = 0; + bool classified = false, bits_counted = false, cksumed = false; + u8 new_bits = 0; /* valid if bits_counted is true */ + u64 cksum = 0; /* valid if cksumed is true */ + +#define classify_if_necessary() \ + do { \ + \ + if (!classified) { \ + \ + classify_counts(&afl->fsrv); \ + classified = true; \ + \ + } \ + \ + } while (0) + +#define calculate_cksum_if_necessary() \ + do { \ + \ + if (!cksumed) { \ + \ + classify_if_necessary(); \ + cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); \ + cksumed = true; \ + \ + } \ + \ + } while (0) + +#define calculate_new_bits_if_necessary() \ + do { \ + \ + if (!bits_counted) { \ + \ + if (classified) { \ + \ + new_bits = has_new_bits(afl, afl->virgin_bits); \ + \ + } else { \ + \ + new_bits = \ + has_new_bits_unclassified(afl, afl->virgin_bits, &classified); \ + \ + } \ + bits_counted = true; \ + \ + } \ + \ + } while (0) + afl->san_case_status = 0; /* Update path frequency. */ @@ -513,11 +563,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, only be used for special schedules */ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { - classify_counts(&afl->fsrv); - classified = 1; - need_hash = 0; - - cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + calculate_cksum_if_necessary(); /* Saturated increment */ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)) @@ -551,17 +597,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, if (unlikely(afl->san_binary_length) && unlikely(afl->san_abstraction == COVERAGE_INCREASE)) { - if (classified) { - - /* We could have classified the bits in SAND with COVERAGE_INCREASE */ - new_bits = has_new_bits(afl, afl->virgin_bits); - - } else { - - new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); - classified = 1; - - } + /* Check if the input increase the coverage */ + calculate_new_bits_if_necessary(); if (unlikely(new_bits)) { feed_san = 1; } @@ -570,15 +607,9 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, if (unlikely(afl->san_binary_length) && likely(afl->san_abstraction == UNIQUE_TRACE)) { - // If schedule is not FAST..RARE, we need to classify counts here // Note: SAND was evaluated under FAST schedule but should also work // with other scedules. - if (!classified) { - - classify_counts(&afl->fsrv); - classified = 1; - - } + classify_if_necessary(); cksum_unique = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); @@ -638,23 +669,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ - if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) { - - /* If we are in coverage increasing abstraction and have fed input to - sanitizers, we are sure it has new bits.*/ - if (classified) { - - /* We could have classified the bits in SAND with UNIQUE_TRACE */ - new_bits = has_new_bits(afl, afl->virgin_bits); - - } else { - - new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); - classified = 1; - - } - - } + calculate_new_bits_if_necessary(); if (likely(!new_bits)) { @@ -677,6 +692,11 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, save_to_queue: + /* these calculations are necessary because some code flow may jump here via + goto */ + calculate_cksum_if_necessary(); + calculate_new_bits_if_necessary(); + #ifndef SIMPLE_FILES if (!afl->afl_env.afl_sha1_filenames) { @@ -758,6 +778,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, #endif + afl->queue_top->exec_cksum = cksum; + if (new_bits == 2) { afl->queue_top->has_new_cov = 1; @@ -765,17 +787,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, } - if (unlikely(need_hash && new_bits)) { - - /* due to classify counts we have to recalculate the checksum */ - afl->queue_top->exec_cksum = - hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - need_hash = 0; - - } - /* For AFLFast schedules we update the new queue entry */ - if (likely(cksum)) { + if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { afl->queue_top->n_fuzz_entry = cksum % N_FUZZ_SIZE; afl->n_fuzz[afl->queue_top->n_fuzz_entry] = 1; @@ -874,12 +887,9 @@ may_save_fault: } new_fault = fuzz_run_target(afl, &afl->fsrv, afl->hang_tmout); - if (!classified) { - - classify_counts(&afl->fsrv); - classified = 1; - - } + classified = false; + bits_counted = false; + cksumed = false; /* A corner case that one user reported bumping into: increasing the timeout actually uncovers a crash. Make sure we don't discard it if From 55d534cd6d1b88bce9bbb9daa9deac1b1ff8027b Mon Sep 17 00:00:00 2001 From: Kuang-che Wu Date: Fri, 23 May 2025 10:39:03 +0800 Subject: [PATCH 15/20] extract function afl_fsrv_setup_preload --- include/forkserver.h | 1 + src/afl-analyze.c | 62 +++----------------------------------------- src/afl-forkserver.c | 57 ++++++++++++++++++++++++++++++++++++++++ src/afl-showmap.c | 55 +-------------------------------------- src/afl-tmin.c | 56 ++------------------------------------- 5 files changed, 65 insertions(+), 166 deletions(-) diff --git a/include/forkserver.h b/include/forkserver.h index db3bfcb3..41f85327 100644 --- a/include/forkserver.h +++ b/include/forkserver.h @@ -242,6 +242,7 @@ typedef enum fsrv_run_result { void afl_fsrv_init(afl_forkserver_t *fsrv); void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from); +void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0); void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv, volatile u8 *stop_soon_p, u8 debug_child_output); u32 afl_fsrv_get_mapsize(afl_forkserver_t *fsrv, char **argv, diff --git a/src/afl-analyze.c b/src/afl-analyze.c index 89a27f63..a006498a 100644 --- a/src/afl-analyze.c +++ b/src/afl-analyze.c @@ -75,7 +75,6 @@ static bool edges_only, /* Ignore hit counts? */ static volatile u8 stop_soon; /* Ctrl-C pressed? */ static u8 *target_path; -static u8 frida_mode; static u8 qemu_mode; static u8 cs_mode; static u32 map_size = MAP_SIZE; @@ -628,9 +627,7 @@ static void handle_stop_sig(int sig) { static void set_up_environment(char **argv) { - u8 *x; - char *afl_preload; - char *frida_afl_preload = NULL; + u8 *x; fsrv.dev_null_fd = open("/dev/null", O_RDWR); if (fsrv.dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -672,57 +669,7 @@ static void set_up_environment(char **argv) { } set_sanitizer_defaults(); - - if (get_afl_env("AFL_PRELOAD")) { - - if (qemu_mode) { - - /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ - - } else if (frida_mode) { - - afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - if (afl_preload) { - - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - - } else { - - frida_afl_preload = alloc_printf("%s", frida_binary); - - } - - ck_free(frida_binary); - - setenv("LD_PRELOAD", frida_afl_preload, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); -#endif - - } else { - - /* CoreSight mode uses the default behavior. */ - - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); -#endif - - } - - } else if (frida_mode) { - - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - setenv("LD_PRELOAD", frida_binary, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); -#endif - ck_free(frida_binary); - - } - - if (frida_afl_preload) { ck_free(frida_afl_preload); } + afl_fsrv_setup_preload(&fsrv, argv[0]); } @@ -936,10 +883,9 @@ int main(int argc, char **argv_orig, char **envp) { case 'O': /* FRIDA mode */ - if (frida_mode) { FATAL("Multiple -O options not supported"); } + if (fsrv.frida_mode) { FATAL("Multiple -O options not supported"); } - frida_mode = 1; - fsrv.frida_mode = frida_mode; + fsrv.frida_mode = true; setenv("AFL_FRIDA_INST_SEED", "1", 1); break; diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index b5fec704..e23bf9a0 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -320,6 +320,63 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { } +void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) { + + char *afl_preload; + char *frida_afl_preload = NULL; + if (get_afl_env("AFL_PRELOAD")) { + + if (fsrv->qemu_mode) { + + /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + + } else if (fsrv->frida_mode) { + + afl_preload = getenv("AFL_PRELOAD"); + u8 *frida_binary = find_afl_binary(argv0, "afl-frida-trace.so"); + if (afl_preload) { + + frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); + + } else { + + frida_afl_preload = alloc_printf("%s", frida_binary); + + } + + ck_free(frida_binary); + + setenv("LD_PRELOAD", frida_afl_preload, 1); +#ifdef __APPLE__ + setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); +#endif + + } else { + + /* CoreSight mode uses the default behavior. */ + + setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); +#ifdef __APPLE__ + setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); +#endif + + } + + } else if (fsrv->frida_mode) { + + u8 *frida_binary = find_afl_binary(argv0, "afl-frida-trace.so"); + setenv("LD_PRELOAD", frida_binary, 1); +#ifdef __APPLE__ + setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); +#endif + ck_free(frida_binary); + + } + + if (frida_afl_preload) { ck_free(frida_afl_preload); } + +} + /* Wrapper for select() and read(), reading a 32 bit var. Returns the time passed to read. If the wait times out, returns timeout_ms + 1; diff --git a/src/afl-showmap.c b/src/afl-showmap.c index bec328f4..bd0594dc 100644 --- a/src/afl-showmap.c +++ b/src/afl-showmap.c @@ -714,61 +714,8 @@ static void handle_stop_sig(int sig) { static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { - char *afl_preload; - char *frida_afl_preload = NULL; - set_sanitizer_defaults(); - - if (get_afl_env("AFL_PRELOAD")) { - - if (fsrv->qemu_mode) { - - /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ - - } else if (fsrv->frida_mode) { - - afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - if (afl_preload) { - - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - - } else { - - frida_afl_preload = alloc_printf("%s", frida_binary); - - } - - ck_free(frida_binary); - - setenv("LD_PRELOAD", frida_afl_preload, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); -#endif - - } else { - - /* CoreSight mode uses the default behavior. */ - - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); -#endif - - } - - } else if (fsrv->frida_mode) { - - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - setenv("LD_PRELOAD", frida_binary, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); -#endif - ck_free(frida_binary); - - } - - if (frida_afl_preload) { ck_free(frida_afl_preload); } + afl_fsrv_setup_preload(fsrv, argv[0]); } diff --git a/src/afl-tmin.c b/src/afl-tmin.c index 894924cd..60f0c84f 100644 --- a/src/afl-tmin.c +++ b/src/afl-tmin.c @@ -899,9 +899,7 @@ static void handle_stop_sig(int sig) { static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { - u8 *x; - char *afl_preload; - char *frida_afl_preload = NULL; + u8 *x; fsrv->dev_null_fd = open("/dev/null", O_RDWR); if (fsrv->dev_null_fd < 0) { PFATAL("Unable to open /dev/null"); } @@ -945,57 +943,7 @@ static void set_up_environment(afl_forkserver_t *fsrv, char **argv) { } set_sanitizer_defaults(); - - if (get_afl_env("AFL_PRELOAD")) { - - if (fsrv->qemu_mode) { - - /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ - - } else if (fsrv->frida_mode) { - - afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - if (afl_preload) { - - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - - } else { - - frida_afl_preload = alloc_printf("%s", frida_binary); - - } - - ck_free(frida_binary); - - setenv("LD_PRELOAD", frida_afl_preload, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); -#endif - - } else { - - /* CoreSight mode uses the default behavior. */ - - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); -#endif - - } - - } else if (fsrv->frida_mode) { - - u8 *frida_binary = find_afl_binary(argv[0], "afl-frida-trace.so"); - setenv("LD_PRELOAD", frida_binary, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); -#endif - ck_free(frida_binary); - - } - - if (frida_afl_preload) { ck_free(frida_afl_preload); } + afl_fsrv_setup_preload(fsrv, argv[0]); } From d62a885f0fe02a612e702dcaf87b71e7b5c1ddb4 Mon Sep 17 00:00:00 2001 From: Kuang-che Wu Date: Fri, 23 May 2025 10:48:56 +0800 Subject: [PATCH 16/20] simplify code --- src/afl-forkserver.c | 61 +++++++++++++------------------------------- 1 file changed, 18 insertions(+), 43 deletions(-) diff --git a/src/afl-forkserver.c b/src/afl-forkserver.c index e23bf9a0..5bf300a3 100644 --- a/src/afl-forkserver.c +++ b/src/afl-forkserver.c @@ -322,59 +322,34 @@ void afl_fsrv_init_dup(afl_forkserver_t *fsrv_to, afl_forkserver_t *from) { void afl_fsrv_setup_preload(afl_forkserver_t *fsrv, char *argv0) { - char *afl_preload; - char *frida_afl_preload = NULL; - if (get_afl_env("AFL_PRELOAD")) { + /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + if (fsrv->qemu_mode) return; - if (fsrv->qemu_mode) { + u8 *afl_preload = getenv("AFL_PRELOAD"); + u8 *preload_path = NULL; + u8 *frida_binary = NULL; + if (fsrv->frida_mode) + frida_binary = find_afl_binary(argv0, "afl-frida-trace.so"); - /* afl-qemu-trace takes care of converting AFL_PRELOAD. */ + if (afl_preload && frida_binary) + preload_path = alloc_printf("%s:%s", afl_preload, frida_binary); + else if (afl_preload) + preload_path = ck_strdup(afl_preload); + else if (frida_binary) + preload_path = ck_strdup(frida_binary); - } else if (fsrv->frida_mode) { + ck_free(frida_binary); - afl_preload = getenv("AFL_PRELOAD"); - u8 *frida_binary = find_afl_binary(argv0, "afl-frida-trace.so"); - if (afl_preload) { + if (preload_path) { - frida_afl_preload = alloc_printf("%s:%s", afl_preload, frida_binary); - - } else { - - frida_afl_preload = alloc_printf("%s", frida_binary); - - } - - ck_free(frida_binary); - - setenv("LD_PRELOAD", frida_afl_preload, 1); + setenv("LD_PRELOAD", preload_path, 1); #ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_afl_preload, 1); + setenv("DYLD_INSERT_LIBRARIES", preload_path, 1); #endif - - } else { - - /* CoreSight mode uses the default behavior. */ - - setenv("LD_PRELOAD", getenv("AFL_PRELOAD"), 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", getenv("AFL_PRELOAD"), 1); -#endif - - } - - } else if (fsrv->frida_mode) { - - u8 *frida_binary = find_afl_binary(argv0, "afl-frida-trace.so"); - setenv("LD_PRELOAD", frida_binary, 1); -#ifdef __APPLE__ - setenv("DYLD_INSERT_LIBRARIES", frida_binary, 1); -#endif - ck_free(frida_binary); + ck_free(preload_path); } - if (frida_afl_preload) { ck_free(frida_afl_preload); } - } /* Wrapper for select() and read(), reading a 32 bit var. From 77758a13439434bc58903a86b2bf0b089420c298 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 23 May 2025 08:50:33 +0200 Subject: [PATCH 17/20] nits in calibrate_case --- src/afl-fuzz-run.c | 49 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/afl-fuzz-run.c b/src/afl-fuzz-run.c index 2488f142..a6a70c59 100644 --- a/src/afl-fuzz-run.c +++ b/src/afl-fuzz-run.c @@ -495,36 +495,41 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, afl->afl_env.afl_post_process_keep_original = 1; /* we need a dummy run if this is LTO + cmplog */ - if (unlikely(afl->shm.cmplog_mode)) { + /* + if (unlikely(afl->shm.cmplog_mode)) { - (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1); + (void)write_to_testcase(afl, (void **)&use_mem, q->len, 1); - fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); + fault = fuzz_run_target(afl, &afl->fsrv, use_tmout); - /* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, - we want to bail out quickly. */ + // afl->stop_soon is set by the handler for Ctrl+C. When it's pressed, + // we want to bail out quickly. - if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; } + if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; - if (!afl->non_instrumented_mode && !afl->stage_cur && - !count_bytes(afl, afl->fsrv.trace_bits)) { + } - fault = FSRV_RUN_NOINST; - goto abort_calibration; + if (!afl->non_instrumented_mode && + !count_bytes(afl, afl->fsrv.trace_bits)) { + + fault = FSRV_RUN_NOINST; + goto abort_calibration; + + } + + #ifdef INTROSPECTION + if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; } + #endif } -#ifdef INTROSPECTION - if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size; -#endif - - } + */ if (q->exec_cksum) { memcpy(afl->first_trace, afl->fsrv.trace_bits, afl->fsrv.map_size); hnb = has_new_bits(afl, afl->virgin_bits); - if (hnb > new_bits) { new_bits = hnb; } + if (unlikely(hnb > new_bits)) { new_bits = hnb; } } @@ -553,7 +558,7 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; } - if (!afl->non_instrumented_mode && !afl->stage_cur && + if (!afl->non_instrumented_mode && !count_bytes(afl, afl->fsrv.trace_bits)) { fault = FSRV_RUN_NOINST; @@ -562,17 +567,19 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem, } #ifdef INTROSPECTION - if (unlikely(!q->bitsmap_size)) q->bitsmap_size = afl->bitsmap_size; + if (unlikely(!q->bitsmap_size)) { q->bitsmap_size = afl->bitsmap_size; } #endif classify_counts(&afl->fsrv); cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); - if (q->exec_cksum != cksum) { + + if (unlikely(q->exec_cksum != cksum)) { hnb = has_new_bits(afl, afl->virgin_bits); - if (hnb > new_bits) { new_bits = hnb; } - if (q->exec_cksum) { + if (unlikely(hnb > new_bits)) { new_bits = hnb; } + + if (likely(q->exec_cksum)) { u32 i; From 8152def40efbe269afaa6c6dc8611a66d40cedbb Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 23 May 2025 09:18:55 +0200 Subject: [PATCH 18/20] changelog --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 39947c1b..6fc9ae73 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -15,6 +15,8 @@ (thanks to @kcwu for raising the issues and providing support!) - more 64 bit archicture support by @maribu - afl-cc: + - Added instrumenting hidden edges (approx 5% edges were not instrumented, + LLVM sancov overall misses 8% of edges compared to our implementation) - Fix to make AFL_SAN_NO_INST work with gcc_plugin - MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation) - Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues From 7e1dc85450212614287cf0a742ee063277d97103 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Fri, 23 May 2025 09:19:42 +0200 Subject: [PATCH 19/20] nit --- docs/Changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Changelog.md b/docs/Changelog.md index 6fc9ae73..e24c2335 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -17,6 +17,8 @@ - afl-cc: - Added instrumenting hidden edges (approx 5% edges were not instrumented, LLVM sancov overall misses 8% of edges compared to our implementation) + Note that is is currently only implemented for our PCGUARD plugin, not + LTO, CLASSIC, etc.! - Fix to make AFL_SAN_NO_INST work with gcc_plugin - MacOS aflpp driver compilation fix (-fsanitize=fuzzer implementation) - Make AFL_DUMP_MAP_SIZE work even if the target has sanitizer issues From d0df78f07aaccb9e02c4e7babf82a3a9ca2c3c8d Mon Sep 17 00:00:00 2001 From: Kuang-che Wu Date: Sat, 24 May 2025 16:39:31 +0800 Subject: [PATCH 20/20] use functions instead of macros --- src/afl-fuzz-bitmap.c | 99 ++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 52 deletions(-) diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index 5ef1cbf2..e3c114f5 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -472,6 +472,46 @@ void write_crash_readme(afl_state_t *afl) { } +static inline void classify_if_necessary(afl_state_t *afl, bool *classified) { + + if (*classified) return; + classify_counts(&afl->fsrv); + *classified = true; + +} + +static inline void calculate_cksum_if_necessary(afl_state_t *afl, u64 *cksum, + bool *cksumed, + bool *classified) { + + if (*cksumed) return; + classify_if_necessary(afl, classified); + *cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); + *cksumed = true; + +} + +static inline void calculate_new_bits_if_necessary(afl_state_t *afl, + u8 *new_bits, + bool *bits_counted, + bool *classified) { + + if (*bits_counted) return; + + if (*classified) { + + *new_bits = has_new_bits(afl, afl->virgin_bits); + + } else { + + *new_bits = has_new_bits_unclassified(afl, afl->virgin_bits, classified); + + } + + *bits_counted = true; + +} + /* Check if the result of an execve() during routine fuzzing is interesting, save or queue the input test case for further analysis if so. Returns 1 if entry is saved, 0 otherwise. */ @@ -509,52 +549,6 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, u8 new_bits = 0; /* valid if bits_counted is true */ u64 cksum = 0; /* valid if cksumed is true */ -#define classify_if_necessary() \ - do { \ - \ - if (!classified) { \ - \ - classify_counts(&afl->fsrv); \ - classified = true; \ - \ - } \ - \ - } while (0) - -#define calculate_cksum_if_necessary() \ - do { \ - \ - if (!cksumed) { \ - \ - classify_if_necessary(); \ - cksum = hash64(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); \ - cksumed = true; \ - \ - } \ - \ - } while (0) - -#define calculate_new_bits_if_necessary() \ - do { \ - \ - if (!bits_counted) { \ - \ - if (classified) { \ - \ - new_bits = has_new_bits(afl, afl->virgin_bits); \ - \ - } else { \ - \ - new_bits = \ - has_new_bits_unclassified(afl, afl->virgin_bits, &classified); \ - \ - } \ - bits_counted = true; \ - \ - } \ - \ - } while (0) - afl->san_case_status = 0; /* Update path frequency. */ @@ -563,7 +557,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, only be used for special schedules */ if (unlikely(afl->schedule >= FAST && afl->schedule <= RARE)) { - calculate_cksum_if_necessary(); + calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified); /* Saturated increment */ if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF)) @@ -598,7 +592,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, unlikely(afl->san_abstraction == COVERAGE_INCREASE)) { /* Check if the input increase the coverage */ - calculate_new_bits_if_necessary(); + calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, + &classified); if (unlikely(new_bits)) { feed_san = 1; } @@ -609,7 +604,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, // Note: SAND was evaluated under FAST schedule but should also work // with other scedules. - classify_if_necessary(); + classify_if_necessary(afl, &classified); cksum_unique = hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST); @@ -669,7 +664,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, /* Keep only if there are new bits in the map, add to queue for future fuzzing, etc. */ - calculate_new_bits_if_necessary(); + calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified); if (likely(!new_bits)) { @@ -694,8 +689,8 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem, /* these calculations are necessary because some code flow may jump here via goto */ - calculate_cksum_if_necessary(); - calculate_new_bits_if_necessary(); + calculate_cksum_if_necessary(afl, &cksum, &cksumed, &classified); + calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified); #ifndef SIMPLE_FILES