mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-11 17:51:32 +00:00
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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"); }
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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]);
|
||||
|
||||
}
|
||||
|
||||
|
@ -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]);
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user