From c00d01bc7b386ca2c79b722f3541ebeefb4da334 Mon Sep 17 00:00:00 2001 From: vanhauser-thc Date: Sun, 2 Jun 2024 16:37:53 +0200 Subject: [PATCH] score values --- instrumentation/SanitizerCoverageLTO.so.cc | 90 +++++++++++++++++-- .../SanitizerCoveragePCGUARD.so.cc | 12 +-- instrumentation/afl-llvm-common.cc | 84 +++++++++++++---- instrumentation/compare-transform-pass.so.cc | 20 ++--- src/afl-fuzz-bitmap.c | 7 +- 5 files changed, 170 insertions(+), 43 deletions(-) diff --git a/instrumentation/SanitizerCoverageLTO.so.cc b/instrumentation/SanitizerCoverageLTO.so.cc index a09f28a9..4ad952e5 100644 --- a/instrumentation/SanitizerCoverageLTO.so.cc +++ b/instrumentation/SanitizerCoverageLTO.so.cc @@ -60,6 +60,8 @@ #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/IR/PassManager.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopPass.h" #include "config.h" #include "debug.h" @@ -172,6 +174,7 @@ SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) { } +using LoopInfoCallback = function_ref; using DomTreeCallback = function_ref; using PostDomTreeCallback = function_ref; @@ -187,13 +190,15 @@ class ModuleSanitizerCoverageLTO } bool instrumentModule(Module &M, DomTreeCallback DTCallback, - PostDomTreeCallback PDTCallback); + PostDomTreeCallback PDTCallback, + LoopInfoCallback LCallback); PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); private: void instrumentFunction(Function &F, DomTreeCallback DTCallback, - PostDomTreeCallback PDTCallback); + PostDomTreeCallback PDTCallback, + LoopInfoCallback LCallback); /* void InjectCoverageForIndirectCalls(Function &F, ArrayRef IndirCalls);*/ @@ -250,6 +255,7 @@ class ModuleSanitizerCoverageLTO uint32_t afl_global_id = 0; uint32_t unhandled = 0; uint32_t select_cnt = 0; + uint32_t dump_cc = 0, dump_vc = 0; uint32_t instrument_ctx = 0; uint32_t instrument_ctx_max_depth = 0; uint32_t extra_ctx_inst = 0; @@ -291,6 +297,7 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass { AU.addRequired(); AU.addRequired(); + AU.addRequired(); } @@ -319,7 +326,15 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass { }; - return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback); + auto LoopCallback = [this](Function &F) -> const LoopInfo * { + + return &this->getAnalysis(F).getLoopInfo(); + + }; + + ModuleSancov.instrumentModule(M, DTCallback, PDTCallback, LoopCallback); + + return 1; } @@ -372,15 +387,21 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M, }; - if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback)) - return PreservedAnalyses::none(); + auto LoopCallback = [&FAM](Function &F) -> const LoopInfo * { - return PreservedAnalyses::all(); + return &FAM.getResult(F); + + }; + + ModuleSancov.instrumentModule(M, DTCallback, PDTCallback, LoopCallback); + + return PreservedAnalyses::none(); } bool ModuleSanitizerCoverageLTO::instrumentModule( - Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { + Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback, + LoopInfoCallback LCallback) { if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false; /* @@ -474,6 +495,10 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( } + if (getenv("AFL_DUMP_CYCLOMATIC_COMPLEXITY")) { dump_cc = 1; } + + if (getenv("AFL_DUMP_VULNERABILITY_COMPLEXITY")) { dump_vc = 1; } + skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO"); use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST"); @@ -1057,7 +1082,7 @@ bool ModuleSanitizerCoverageLTO::instrumentModule( // M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy); for (auto &F : M) - instrumentFunction(F, DTCallback, PDTCallback); + instrumentFunction(F, DTCallback, PDTCallback, LCallback); // AFL++ START if (dFile.is_open()) dFile.close(); @@ -1347,7 +1372,8 @@ Function *returnOnlyCaller(Function *F) { } void ModuleSanitizerCoverageLTO::instrumentFunction( - Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) { + Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback, + LoopInfoCallback LCallback) { if (F.empty()) return; if (F.getName().find(".module_ctor") != std::string::npos) @@ -1421,6 +1447,7 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( const DominatorTree *DT = DTCallback(F); const PostDominatorTree *PDT = PDTCallback(F); + const LoopInfo *LI = LCallback(F); bool IsLeafFunc = true; uint32_t skip_next = 0; uint32_t call_counter = 0, call_depth = 0; @@ -1955,6 +1982,51 @@ void ModuleSanitizerCoverageLTO::instrumentFunction( } + unsigned int score = 0; + + if (dump_cc) { score += calcCyclomaticComplexity(&F, LI); } + if (dump_vc) { score += calcVulnerabilityScore(&F, LI, DT, PDT); } + + if (score) { + + BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt(); + IRBuilder<> builder(&*IP); + + // Access the int32 value at u8 offset 1 (unaligned access) + LoadInst *MapPtr = + builder.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr); + llvm::Value *CastToInt8Ptr = + builder.CreateBitCast(MapPtr, llvm::PointerType::get(Int8Ty, 0)); + llvm::Value *Int32Ptr = builder.CreateGEP( + Int8Ty, CastToInt8Ptr, llvm::ConstantInt::get(Int32Ty, 1)); + llvm::Value *CastToInt32Ptr = + builder.CreateBitCast(Int32Ptr, llvm::PointerType::get(Int32Ty, 0)); + + // Load the unaligned int32 value + llvm::LoadInst *Load = builder.CreateLoad(Int32Ty, CastToInt32Ptr); + Load->setAlignment(llvm::Align(1)); + + // Value to add + llvm::Value *ValueToAdd = llvm::ConstantInt::get(Int32Ty, score); + + // Perform addition and check for wrap around + llvm::Value *Add = + builder.CreateAdd(Load, ValueToAdd, "addValue", true, true); + + // Check if addition wrapped (unsigned) + llvm::Value *DidWrap = builder.CreateICmpULT(Add, Load, "didWrap"); + + // Select the maximum value if there was a wrap, otherwise use the result + llvm::Value *MaxInt32 = llvm::ConstantInt::get(Int32Ty, UINT32_MAX); + llvm::Value *Result = + builder.CreateSelect(DidWrap, MaxInt32, Add, "selectMaxOrResult"); + + // Store the result back at the same unaligned offset + llvm::StoreInst *Store = builder.CreateStore(Result, CastToInt32Ptr); + Store->setAlignment(llvm::Align(1)); + + } + InjectCoverage(F, BlocksToInstrument, IsLeafFunc); // InjectCoverageForIndirectCalls(F, IndirCalls); diff --git a/instrumentation/SanitizerCoveragePCGUARD.so.cc b/instrumentation/SanitizerCoveragePCGUARD.so.cc index f66ca4eb..208b9d81 100644 --- a/instrumentation/SanitizerCoveragePCGUARD.so.cc +++ b/instrumentation/SanitizerCoveragePCGUARD.so.cc @@ -660,14 +660,10 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( } - InjectCoverage(F, BlocksToInstrument, IsLeafFunc); - // InjectTraceForCmp(F, CmpTraceTargets); - // InjectTraceForSwitch(F, SwitchTraceTargets); - unsigned int score = 0; - if (dump_cc) { score = calcCyclomaticComplexity(&F, LI); } - if (dump_vc) { score = calcVulnerabilityScore(&F, LI, DT, PDT); } + if (dump_cc) { score += calcCyclomaticComplexity(&F, LI); } + if (dump_vc) { score += calcVulnerabilityScore(&F, LI, DT, PDT); } if (score) { @@ -709,6 +705,10 @@ void ModuleSanitizerCoverageAFL::instrumentFunction( } + InjectCoverage(F, BlocksToInstrument, IsLeafFunc); + // InjectTraceForCmp(F, CmpTraceTargets); + // InjectTraceForSwitch(F, SwitchTraceTargets); + } GlobalVariable *ModuleSanitizerCoverageAFL::CreateFunctionLocalArrayInSection( diff --git a/instrumentation/afl-llvm-common.cc b/instrumentation/afl-llvm-common.cc index 85aea005..a11abf5e 100644 --- a/instrumentation/afl-llvm-common.cc +++ b/instrumentation/afl-llvm-common.cc @@ -14,7 +14,7 @@ #include #include -#if LLVM_VERSION_MAJOR > 12 +#if LLVM_VERSION_MAJOR >= 13 #include "llvm/Support/raw_ostream.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" @@ -28,6 +28,8 @@ #include "llvm/Analysis/PostDominators.h" #endif +// #define LEOPARD_USE_WEIGHTS 1 + #define IS_EXTERN extern #include "afl-llvm-common.h" @@ -38,7 +40,46 @@ static std::list allowListFunctions; static std::list denyListFiles; static std::list denyListFunctions; -#if LLVM_VERSION_MAJOR > 12 +#if LLVM_VERSION_MAJOR >= 13 +// Leopard complexity calculations + + #ifndef LEOPARD_USE_WEIGHTS + #define C1_WEIGHT 1.0 + #define C2_WEIGHT 1.0 + #define C3_WEIGHT 1.0 + #define C4_WEIGHT 1.0 + #define V1_WEIGHT 1.0 + #define V2_WEIGHT 1.0 + #define V3_WEIGHT 1.0 + #define V4_WEIGHT 1.0 + #define V5_WEIGHT 1.0 + #define V6_WEIGHT 1.0 + #define V7_WEIGHT 1.0 + #define V8_WEIGHT 1.0 + #define V9_WEIGHT 1.0 + #define V10_WEIGHT 1.0 + #define V11_WEIGHT 1.0 + #else + // Cyclomatic weights + #define C1_WEIGHT 1.0 + #define C2_WEIGHT 1.0 + #define C3_WEIGHT 1.0 + #define C4_WEIGHT 1.0 + + // Vulnerability weights + #define V1_WEIGHT 1.5 + #define V2_WEIGHT 3.25 + #define V3_WEIGHT 4.25 + #define V4_WEIGHT 3.0 + #define V5_WEIGHT 4.25 + #define V6_WEIGHT 7.75 + #define V7_WEIGHT 2.5 + #define V8_WEIGHT 2.5 + #define V9_WEIGHT 4.0 + #define V10_WEIGHT 5.25 + #define V11_WEIGHT 3.5 + #endif + static void countNestedLoops(Loop *L, int depth, unsigned int &loopCount, unsigned int &nestedLoopCount, unsigned int &maxNestingLevel) { @@ -105,20 +146,23 @@ unsigned int calcCyclomaticComplexity(llvm::Function *F, // Cyclomatic Complexity V(G) = E - N + 2P // For a single function, P (number of connected components) is 1 // Calls are considered to be an edge - unsigned int CC = 2 + numCalls + numEdges - numBlocks + numLoops + - numNestedLoops + maxLoopNesting; + unsigned int cc = + (unsigned int)(C1_WEIGHT * (double)(2 + numCalls + numEdges - numBlocks) + + C2_WEIGHT * (double)numLoops + + C3_WEIGHT * (double)numNestedLoops + + C4_WEIGHT * (double)maxLoopNesting); // if (debug) { fprintf(stderr, "CyclomaticComplexity for %s: %u (calls=%u edges=%u blocks=%u " "loops=%u nested_loops=%u max_loop_nesting_level=%u)\n", - F->getName().str().c_str(), CC, numCalls, numEdges, numBlocks, + F->getName().str().c_str(), cc, numCalls, numEdges, numBlocks, numLoops, numNestedLoops, maxLoopNesting); //} - return CC; + return cc; } @@ -126,7 +170,7 @@ unsigned int calcVulnerabilityScore(llvm::Function *F, const llvm::LoopInfo *LI, const llvm::DominatorTree *DT, const llvm::PostDominatorTree *PDT) { - unsigned int Score = 0; + unsigned int score = 0; // V1 and V2 unsigned paramCount = F->arg_size(); unsigned calledParamCount = 0; @@ -254,10 +298,17 @@ unsigned int calcVulnerabilityScore(llvm::Function *F, const llvm::LoopInfo *LI, } - Score = paramCount + calledParamCount + pointerArithCount + - totalPointerArithParams + maxPointerArithVars + maxNestingLevel + - maxControlDependentControls + maxDataDependentControls + - ifWithoutElseCount + controlPredicateVarCount; + score = (unsigned int)(V1_WEIGHT * (double)paramCount + + V2_WEIGHT * (double)calledParamCount + + V3_WEIGHT * (double)pointerArithCount + + V4_WEIGHT * (double)totalPointerArithParams + + V5_WEIGHT * (double)maxPointerArithVars + + V6_WEIGHT * (double)nestedControlStructCount + + V7_WEIGHT * (double)maxNestingLevel + + V8_WEIGHT * (double)maxControlDependentControls + + V9_WEIGHT * (double)maxDataDependentControls + + V10_WEIGHT * (double)ifWithoutElseCount + + V11_WEIGHT * (double)controlPredicateVarCount); fprintf(stderr, "VulnerabilityScore for %s: %u (paramCount=%u " @@ -265,13 +316,13 @@ unsigned int calcVulnerabilityScore(llvm::Function *F, const llvm::LoopInfo *LI, "maxPointerArithVars=%u|maxNestingLevel=%u " "maxControlDependentControls=%u maxDataDependentControls=%u " "ifWithoutElseCount=%u controlPredicateVarCount=%u)\n", - F->getName().str().c_str(), Score, paramCount, calledParamCount, + F->getName().str().c_str(), score, paramCount, calledParamCount, pointerArithCount, totalPointerArithParams, maxPointerArithVars, maxNestingLevel, maxControlDependentControls, maxDataDependentControls, ifWithoutElseCount, controlPredicateVarCount); - return Score; + return score; } @@ -342,11 +393,10 @@ bool isIgnoreFunction(const llvm::Function *F) { for (auto const &ignoreListFunc : ignoreList) { - -#if LLVM_VERSION_MAJOR < 19 - if (F->getName().startswith(ignoreListFunc)) { return true; } -#else +#if LLVM_VERSION_MAJOR >= 19 if (F->getName().starts_with(ignoreListFunc)) { return true; } +#else + if (F->getName().startswith(ignoreListFunc)) { return true; } #endif } diff --git a/instrumentation/compare-transform-pass.so.cc b/instrumentation/compare-transform-pass.so.cc index 8628c477..9465e014 100644 --- a/instrumentation/compare-transform-pass.so.cc +++ b/instrumentation/compare-transform-pass.so.cc @@ -57,6 +57,12 @@ #include #include "afl-llvm-common.h" +#if LLVM_MAJOR >= 19 + #define STARTSWITH starts_with +#else + #define STARTSWITH startswith +#endif + using namespace llvm; namespace { @@ -531,17 +537,11 @@ bool CompareTransform::transformCmps(Module &M, const bool processStrcmp, } -#if LLVM_VERSION_MAJOR < 19 - #define FUCKLLVM startswith -#else - #define FUCKLLVM starts_with -#endif - if (!isSizedcmp) needs_null = true; - if (Callee->getName().FUCKLLVM("g_") || - Callee->getName().FUCKLLVM("curl_") || - Callee->getName().FUCKLLVM("Curl_") || - Callee->getName().FUCKLLVM("xml")) + if (Callee->getName().STARTSWITH("g_") || + Callee->getName().STARTSWITH("curl_") || + Callee->getName().STARTSWITH("Curl_") || + Callee->getName().STARTSWITH("xml")) nullCheck = true; Value *sizedValue = isSizedcmp ? callInst->getArgOperand(2) : NULL; diff --git a/src/afl-fuzz-bitmap.c b/src/afl-fuzz-bitmap.c index b33f7154..888f45d2 100644 --- a/src/afl-fuzz-bitmap.c +++ b/src/afl-fuzz-bitmap.c @@ -482,7 +482,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) { u64 cksum = 0; // will be classified away otherwise - afl->current_score = *(u32 *)((u8 *)afl->fsrv.trace_bits + 1); + if (unlikely((afl->current_score = *(u32 *)((u8 *)afl->fsrv.trace_bits + 1)) > + 0)) { + + memset(afl->fsrv.trace_bits + 1, 0, 4); + + } /* Update path frequency. */