Merge pull request #2450 from AFLplusplus/dev

push to stable
This commit is contained in:
van Hauser
2025-05-24 13:24:03 +02:00
committed by GitHub
14 changed files with 670 additions and 400 deletions

View File

@ -15,6 +15,10 @@
(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)
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

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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"); }
}

View File

@ -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"
@ -76,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"
@ -206,7 +207,8 @@ 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, skippedbb = 0,
dump_cc = 0;
GlobalVariable *AFLMapPtr = NULL;
ConstantInt *One = NULL;
ConstantInt *Zero = NULL;
@ -279,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"); }
}
@ -505,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 selects.",
instr, modeline, selects, unhandled);
"%u handled and %u unhandled special instructions.%s",
instr, modeline, selects + hidden, unhandled, buf);
}
@ -781,11 +790,14 @@ 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, skip_blocks = 0;
static uint32_t first = 1;
for (auto &BB : F) {
bool block_is_instrumented = false;
for (auto &IN : BB) {
CallInst *callInst = nullptr;
@ -799,11 +811,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;
}
@ -811,53 +823,183 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
if (!FuncName.compare(StringRef("__afl_coverage_interesting"))) {
cnt_cov++;
block_is_instrumented = true;
}
}
SelectInst *selectInst = nullptr;
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
if ((selectInst = dyn_cast<SelectInst>(&IN))) {
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
// || isa<PHINode>(&IN)
cnt_sel++;
cnt_sel_inc += 2;
bool usedInBranch = false, usedInSelectDecision = false;
}
for (auto *U : IN.users()) {
else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
if (isa<BranchInst>(U)) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
usedInBranch = true;
break;
cnt_sel++;
cnt_sel_inc += (tt->getElementCount().getKnownMinValue() * 2);
}
if (auto *sel = dyn_cast<SelectInst>(U)) {
if (icmp && sel->getCondition() == icmp) {
usedInSelectDecision = true;
} else if (fcmp && sel->getCondition() == fcmp) {
usedInSelectDecision = true;
}
}
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
block_is_instrumented = true;
SelectInst *selectInst;
ICmpInst *icmp;
FCmpInst *fcmp;
// PHINode *phiInst;
// errs() << "IN: " << *(&IN) << "\n";
/* if ((phiInst = dyn_cast<PHINode>(&IN))) {
cnt_hidden_sel++;
cnt_hidden_sel_inc += phiInst->getNumIncomingValues();
} else*/
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (icmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
if (fcmp->getType()->isIntegerTy(1)) {
cnt_sel++;
cnt_sel_inc += 2;
} else {
unhandled++;
}
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
Value *c = selectInst->getCondition();
auto t = c->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
cnt_sel++;
cnt_sel_inc += 2;
} else if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(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() &&
llvm::is_contained(AllBlocks, &BB)) {
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);
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;
// uint32_t skip_phi = 0;
for (auto &BB : F) {
// errs() << *(&BB) << "\n";
for (auto &IN : BB) {
// errs() << *(&IN) << "\n";
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
@ -875,15 +1017,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),
@ -897,132 +1030,324 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
SelectInst *selectInst = nullptr;
bool instrumentInst = false;
ICmpInst *icmp;
FCmpInst *fcmp;
if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
if ((icmp = dyn_cast<ICmpInst>(&IN)) ||
(fcmp = dyn_cast<FCmpInst>(&IN)) || isa<SelectInst>(&IN)) {
uint32_t vector_cnt = 0;
Value *condition = selectInst->getCondition();
Value *result;
auto t = condition->getType();
IRBuilder<> IRB(selectInst->getNextNode());
// || isa<PHINode>(&IN)
if (t->getTypeID() == llvm::Type::IntegerTyID) {
bool usedInBranch = false, usedInSelectDecision = false;
if (!FunctionGuardArray) {
for (auto *U : IN.users()) {
fprintf(stderr,
"SANCOV: FunctionGuardArray is NULL, failed to emit "
"instrumentation.");
continue;
if (isa<BranchInst>(U)) {
usedInBranch = true;
break;
}
auto GuardPtr1 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
if (auto *sel = dyn_cast<SelectInst>(U)) {
auto GuardPtr2 = IRB.CreateIntToPtr(
IRB.CreateAdd(
IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
ConstantInt::get(
IntptrTy,
(cnt_cov + local_selects++ + AllBlocks.size()) * 4)),
Int32PtrTy);
if (icmp && sel->getCondition() == icmp) {
result = IRB.CreateSelect(condition, GuardPtr1, GuardPtr2);
usedInSelectDecision = true;
break;
} else
} else if (fcmp && sel->getCondition() == fcmp) {
#if LLVM_VERSION_MAJOR >= 14
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
uint32_t elements = tt->getElementCount().getFixedValue();
vector_cnt = elements;
if (elements) {
FixedVectorType *GuardPtr1 =
FixedVectorType::get(Int32PtrTy, elements);
FixedVectorType *GuardPtr2 =
FixedVectorType::get(Int32PtrTy, elements);
Value *x, *y;
if (!FunctionGuardArray) {
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(
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);
usedInSelectDecision = true;
break;
}
}
} else
}
if (!usedInBranch && !usedInSelectDecision) {
// errs() << "Instrument! " << *(&IN) << "\n";
instrumentInst = true;
}
}
if (instrumentInst) {
Value *result = nullptr;
uint32_t vector_cnt = 0;
SelectInst *selectInst;
// PHINode *phi = nullptr, *newPhi = nullptr;
IRBuilder<> IRB(IN.getNextNode());
if ((icmp = dyn_cast<ICmpInst>(&IN))) {
if (!icmp->getType()->isIntegerTy(1)) { continue; }
if (skip_icmp) {
skip_icmp--;
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 = icmp;
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;
// fprintf(stderr, "Icmp!\n");
} else if ((fcmp = dyn_cast<FCmpInst>(&IN))) {
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,
{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;
// fprintf(stderr, "Fcmp!\n");
/*} else if ((phi = dyn_cast<PHINode>(&IN))) {
if (skip_phi) {
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();
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);
}
result = newPhi;
skip_phi = 1;
// fprintf(stderr, "Phi!\n");
*/
} else if ((selectInst = dyn_cast<SelectInst>(&IN))) {
if (skip_select) {
skip_select = 0;
continue;
} else {
// fprintf(stderr, "Select!\n");
}
Value *condition = selectInst->getCondition();
auto t = condition->getType();
if (t->getTypeID() == llvm::Type::IntegerTyID) {
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(condition, GuardPtr1, GuardPtr2);
skip_select = 1;
} else
#if LLVM_VERSION_MAJOR >= 14
if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
if (tt) {
uint32_t elements = tt->getElementCount().getFixedValue();
vector_cnt = elements;
if (elements) {
FixedVectorType *GuardPtr1 =
FixedVectorType::get(Int32PtrTy, elements);
FixedVectorType *GuardPtr2 =
FixedVectorType::get(Int32PtrTy, elements);
Value *x, *y;
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(
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;
}
}
} 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<Instruction>(result);
PHINode *nphi;
while ((nphi = dyn_cast<PHINode>(inst))) {
// fprintf(stderr, "NEXT!\n");
inst = inst->getNextNode();
}
IRB.SetInsertPoint(inst);
}
*/
LoadInst *MapPtr =
IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
@ -1073,6 +1398,7 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
skip_icmp++;
}
@ -1094,13 +1420,8 @@ bool ModuleSanitizerCoverageAFL::InjectCoverage(
}
skip_next = 1;
instr += vector_cnt;
} else {
skip_next = 0;
}
}
@ -1109,9 +1430,40 @@ 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);
}
}
}
skippedbb += skipped;
/*
if (verifyFunction(F, &errs())) {
errs() << "Broken function after instrumentation\n";
F.print(errs(), nullptr);
report_fatal_error("Invalid IR");
}
*/
return true;

View File

@ -227,7 +227,7 @@ bool AFLCoverage::runOnModule(Module &M) {
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
if (getenv("AFL_LLVM_ONLY_FSRV")) {
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_LLVM_ONLY_FSRV")) {
if (debug) { fprintf(stderr, "Instrument disabled\n"); }
if (debug) { fprintf(stderr, "Instrumentation disabled\n"); }
return true;
}

View File

@ -64,6 +64,8 @@ using namespace llvm;
namespace {
using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
#if LLVM_MAJOR >= 11 /* use new pass manager */
class CmpLogInstructions : public PassInfoMixin<CmpLogInstructions> {
@ -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<Instruction *> 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<CmpInst>(&IN))) {
// skip loop comparisons
if (selectcmpInst->hasOneUse())
if (auto BR = dyn_cast<BranchInst>(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<FunctionAnalysisManagerModuleProxy>(M).getManager();
auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
return &FAM.getResult<DominatorTreeAnalysis>(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 */

View File

@ -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;

View File

@ -320,6 +320,38 @@ 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) {
/* afl-qemu-trace takes care of converting AFL_PRELOAD. */
if (fsrv->qemu_mode) return;
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");
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);
ck_free(frida_binary);
if (preload_path) {
setenv("LD_PRELOAD", preload_path, 1);
#ifdef __APPLE__
setenv("DYLD_INSERT_LIBRARIES", preload_path, 1);
#endif
ck_free(preload_path);
}
}
/* 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;

View File

@ -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);
}
@ -470,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. */
@ -498,13 +540,15 @@ 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 */
afl->san_case_status = 0;
/* Update path frequency. */
@ -513,11 +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)) {
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(afl, &cksum, &cksumed, &classified);
/* Saturated increment */
if (likely(afl->n_fuzz[cksum % N_FUZZ_SIZE] < 0xFFFFFFFF))
@ -551,17 +591,9 @@ 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(afl, &new_bits, &bits_counted,
&classified);
if (unlikely(new_bits)) { feed_san = 1; }
@ -570,15 +602,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(afl, &classified);
cksum_unique =
hash32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
@ -638,23 +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. */
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(afl, &new_bits, &bits_counted, &classified);
if (likely(!new_bits)) {
@ -677,6 +687,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(afl, &cksum, &cksumed, &classified);
calculate_new_bits_if_necessary(afl, &new_bits, &bits_counted, &classified);
#ifndef SIMPLE_FILES
if (!afl->afl_env.afl_sha1_filenames) {
@ -758,6 +773,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 +782,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 +882,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

View File

@ -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;

View File

@ -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]);
}

View File

@ -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]);
}