C(pp) formatting & autotokens fix (#614)

* fix

* a

* format

* .clang-format
This commit is contained in:
Dongjia Zhang 2022-05-04 03:42:43 +09:00 committed by GitHub
parent b0dd25ee95
commit 6b76e53bfa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 408 additions and 454 deletions

148
.clang-format Normal file
View File

@ -0,0 +1,148 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: BeforeHash
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Right
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...

View File

@ -2,8 +2,6 @@
//! They may be inserted as part of mutations during fuzzing.
#[cfg(feature = "std")]
use crate::mutators::str_decode;
#[cfg(target_os = "linux")]
use alloc::string::ToString;
use alloc::vec::Vec;
#[cfg(target_os = "linux")]
use core::slice::from_raw_parts;
@ -110,9 +108,9 @@ impl Tokens {
pub unsafe fn from_ptrs(token_start: *const u8, token_stop: *const u8) -> Result<Self, Error> {
let mut ret = Self::default();
if token_start.is_null() || token_stop.is_null() {
return Err(Error::IllegalArgument("token_start or token_stop is null. If you are using autotokens() you likely did not build your target with the \"AutoTokens\"-pass".to_string()));
return Ok(Self::new());
}
if token_stop <= token_start {
if token_stop < token_start {
return Err(Error::IllegalArgument(format!(
"Tried to create tokens from illegal section: stop < start ({:?} < {:?})",
token_stop, token_start

View File

@ -72,15 +72,35 @@ typedef uint32_t prev_loc_t;
using namespace llvm;
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false), cl::NotHidden);
static cl::opt<uint32_t> InstRatio("inst_ratio", cl::desc("Instrumentation ratio in percentage"), cl::init(100), cl::NotHidden);
static cl::opt<bool> NotZero("not_zero", cl::desc("Never hit 0 again in the hitcount"), cl::init(true), cl::NotHidden);
static cl::opt<uint32_t> Ngram("ngram", cl::desc("Size of the Ngram instrumentation (0 to disable)"), cl::init(0), cl::NotHidden);
static cl::opt<uint32_t> CtxK("ctx_k", cl::desc("Size of the context for K-Ctx context sensitivity (0 to disable)"), cl::init(0), cl::NotHidden);
static cl::opt<bool> Ctx("ctx", cl::desc("Enable full context sensitive coverage"), cl::init(false), cl::NotHidden);
static cl::opt<bool> ThreadSafe("thread_safe", cl::desc("Use the thread safe instrumentation"), cl::init(false), cl::NotHidden);
static cl::opt<bool> DumpCFG("dump_afl_cfg", cl::desc("Dump CFG containing AFL-style edge index"), cl::init(false), cl::NotHidden);
static cl::opt<std::string> DumpCFGPath("dump_afl_cfg_path", cl::desc("Path to dump CFG containing AFL-style edge index"), cl::init(".cfg"), cl::NotHidden);
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false),
cl::NotHidden);
static cl::opt<uint32_t> InstRatio(
"inst_ratio", cl::desc("Instrumentation ratio in percentage"),
cl::init(100), cl::NotHidden);
static cl::opt<bool> NotZero("not_zero",
cl::desc("Never hit 0 again in the hitcount"),
cl::init(true), cl::NotHidden);
static cl::opt<uint32_t> Ngram(
"ngram", cl::desc("Size of the Ngram instrumentation (0 to disable)"),
cl::init(0), cl::NotHidden);
static cl::opt<uint32_t> CtxK(
"ctx_k",
cl::desc(
"Size of the context for K-Ctx context sensitivity (0 to disable)"),
cl::init(0), cl::NotHidden);
static cl::opt<bool> Ctx("ctx",
cl::desc("Enable full context sensitive coverage"),
cl::init(false), cl::NotHidden);
static cl::opt<bool> ThreadSafe("thread_safe",
cl::desc("Use the thread safe instrumentation"),
cl::init(false), cl::NotHidden);
static cl::opt<bool> DumpCFG(
"dump_afl_cfg", cl::desc("Dump CFG containing AFL-style edge index"),
cl::init(false), cl::NotHidden);
static cl::opt<std::string> DumpCFGPath(
"dump_afl_cfg_path",
cl::desc("Path to dump CFG containing AFL-style edge index"),
cl::init(".cfg"), cl::NotHidden);
namespace {
@ -96,7 +116,6 @@ class AFLCoverage : public ModulePass {
#endif
// initInstrumentList();
}
#ifdef USE_NEW_PM
@ -106,11 +125,10 @@ class AFLCoverage : public ModulePass {
#endif
protected:
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
DenseMap<BasicBlock *, int32_t> bb_to_cur_loc;
DenseMap<StringRef, BasicBlock *> entry_bb;
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
DenseMap<BasicBlock *, int32_t> bb_to_cur_loc;
DenseMap<StringRef, BasicBlock *> entry_bb;
};
} // namespace
@ -118,33 +136,30 @@ class AFLCoverage : public ModulePass {
#ifdef USE_NEW_PM
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
return {
LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if 1
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(AFLCoverage());
}
);
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback(
[](StringRef Name, ModulePassManager &MPM, ArrayRef<PipelineElement>) {
if ( Name == "AFLCoverage" ) {
MPM.addPass(AFLCoverage());
return true;
} else {
return false;
}
}
);
#endif
}
};
return {LLVM_PLUGIN_API_VERSION, "AFLCoverage", "v0.1",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if 1
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(AFLCoverage());
});
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback([](StringRef Name,
ModulePassManager &MPM,
ArrayRef<PipelineElement>) {
if (Name == "AFLCoverage") {
MPM.addPass(AFLCoverage());
return true;
} else {
return false;
}
});
#endif
}};
}
#else
@ -156,7 +171,10 @@ PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool AFLCoverage::runOnModule(Module &M) {
#endif
if (Ctx && DumpCFG) FATAL("Does not support dumping CFG with full context sensitive coverage enabled.");
if (Ctx && DumpCFG)
FATAL(
"Does not support dumping CFG with full context sensitive coverage "
"enabled.");
LLVMContext &C = M.getContext();
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
@ -165,7 +183,7 @@ bool AFLCoverage::runOnModule(Module &M) {
IntegerType *IntLocTy =
IntegerType::getIntNTy(C, sizeof(prev_loc_t) * CHAR_BIT);
#endif
uint32_t rand_seed;
uint32_t rand_seed;
unsigned int cur_loc = 0;
#ifdef USE_NEW_PM
@ -205,10 +223,10 @@ bool AFLCoverage::runOnModule(Module &M) {
VectorType *PrevLocTy = NULL;
if (Ngram && (Ngram < 2 || Ngram > NGRAM_SIZE_MAX))
FATAL(
"Bad value of the Ngram size (must be between 2 and NGRAM_SIZE_MAX "
"(%u))",
NGRAM_SIZE_MAX);
FATAL(
"Bad value of the Ngram size (must be between 2 and NGRAM_SIZE_MAX "
"(%u))",
NGRAM_SIZE_MAX);
if (Ngram)
PrevLocSize = Ngram - 1;
@ -219,22 +237,20 @@ bool AFLCoverage::runOnModule(Module &M) {
VectorType *PrevCallerTy = NULL;
if (CtxK > CTX_MAX_K)
FATAL("Bad value of K for K-context sensitivity (must be between 1 and CTX_MAX_K (%u))",
CTX_MAX_K);
FATAL(
"Bad value of K for K-context sensitivity (must be between 1 and "
"CTX_MAX_K (%u))",
CTX_MAX_K);
if (CtxK == 1) {
CtxK = 0;
instrument_ctx = true;
instrument_caller = true; // Enable CALLER instead
}
if (CtxK) {
PrevCallerSize = CtxK;
instrument_ctx = true;
}
#else
@ -371,11 +387,10 @@ bool AFLCoverage::runOnModule(Module &M) {
Constant *PrevLocShuffleMask = ConstantVector::get(PrevLocShuffle);
Constant * PrevCallerShuffleMask = NULL;
Constant *PrevCallerShuffleMask = NULL;
SmallVector<Constant *, 32> PrevCallerShuffle = {UndefValue::get(Int32Ty)};
if (CtxK) {
for (unsigned I = 0; I < PrevCallerSize - 1; ++I)
PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, I));
@ -383,7 +398,6 @@ bool AFLCoverage::runOnModule(Module &M) {
PrevCallerShuffle.push_back(ConstantInt::get(Int32Ty, PrevCallerSize));
PrevCallerShuffleMask = ConstantVector::get(PrevCallerShuffle);
}
#endif
@ -391,7 +405,7 @@ bool AFLCoverage::runOnModule(Module &M) {
// other constants we need
ConstantInt *One = ConstantInt::get(Int8Ty, 1);
Value * PrevCtx = NULL; // CTX sensitive coverage
Value *PrevCtx = NULL; // CTX sensitive coverage
LoadInst *PrevCaller = NULL; // K-CTX coverage
/* Instrument all the things! */
@ -400,7 +414,6 @@ bool AFLCoverage::runOnModule(Module &M) {
// scanForDangerousFunctions(&M);
for (auto &F : M) {
int has_calls = 0;
if (Debug)
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
@ -413,16 +426,13 @@ bool AFLCoverage::runOnModule(Module &M) {
std::list<Value *> todo;
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
// Context sensitive coverage
if (instrument_ctx && &BB == &F.getEntryBlock()) {
#ifdef HAVE_VECTOR_INTRINSICS
if (CtxK) {
PrevCaller = IRB.CreateLoad(AFLPrevCaller);
PrevCaller->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
@ -430,7 +440,6 @@ bool AFLCoverage::runOnModule(Module &M) {
IRB.CreateZExt(IRB.CreateXorReduce(PrevCaller), IRB.getInt32Ty());
} else
#endif
{
@ -440,42 +449,31 @@ bool AFLCoverage::runOnModule(Module &M) {
PrevCtxLoad->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
PrevCtx = PrevCtxLoad;
}
// does the function have calls? and is any of the calls larger than one
// basic block?
for (auto &BB_2 : F) {
if (has_calls) break;
for (auto &IN : BB_2) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
Function *Callee = callInst->getCalledFunction();
if (!Callee || Callee->size() < function_minimum_size)
continue;
else {
has_calls = 1;
break;
}
}
}
}
// if yes we store a context ID for this function in the global var
if (has_calls) {
Value *NewCtx = ConstantInt::get(Int32Ty, RandBelow(map_size));
#ifdef HAVE_VECTOR_INTRINSICS
if (CtxK) {
Value *ShuffledPrevCaller = IRB.CreateShuffleVector(
PrevCaller, UndefValue::get(PrevCallerTy),
PrevCallerShuffleMask);
@ -488,7 +486,6 @@ bool AFLCoverage::runOnModule(Module &M) {
MDNode::get(C, None));
} else
#endif
{
@ -496,11 +493,8 @@ bool AFLCoverage::runOnModule(Module &M) {
StoreInst *StoreCtx = IRB.CreateStore(NewCtx, AFLContext);
StoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
}
if (RandBelow(100) >= InstRatio) continue;
@ -523,7 +517,6 @@ bool AFLCoverage::runOnModule(Module &M) {
// fprintf(stderr, "BB %u: ", cur_loc);
for (pred_iterator PI = pred_begin(&BB), E = pred_end(&BB); PI != E;
++PI) {
BasicBlock *Pred = *PI;
int count = 0;
@ -532,30 +525,24 @@ bool AFLCoverage::runOnModule(Module &M) {
for (succ_iterator SI = succ_begin(Pred), E = succ_end(Pred); SI != E;
++SI) {
BasicBlock *Succ = *SI;
// if (count > 0)
// fprintf(stderr, "|");
if (Succ != NULL) count++;
// fprintf(stderr, "%p", Succ);
}
if (count > 1) more_than_one = 1;
}
// fprintf(stderr, " == %d\n", more_than_one);
if (F.size() > 1 && more_than_one != 1) {
// in CTX mode we have to restore the original context for the caller -
// she might be calling other functions which need the correct CTX
if (instrument_ctx && has_calls) {
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst *RestoreCtx;
@ -567,13 +554,10 @@ bool AFLCoverage::runOnModule(Module &M) {
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
continue;
}
#endif
@ -630,23 +614,23 @@ bool AFLCoverage::runOnModule(Module &M) {
/* Update bitmap */
if (ThreadSafe) { /* Atomic */
/*
#if LLVM_VERSION_MAJOR < 9
if (neverZero_counters_str !=
NULL) { // with llvm 9 we make this the default as the bug
in llvm
// is then fixed
#else
if (NotZero) {
#endif
// register MapPtrIdx in a todo list
todo.push_back(MapPtrIdx);
} else {
*/
if (ThreadSafe) { /* Atomic */
/*
#if LLVM_VERSION_MAJOR < 9
if (neverZero_counters_str !=
NULL) { // with llvm 9 we make this the default as the bug
in llvm
// is then fixed
#else
if (NotZero) {
#endif
// register MapPtrIdx in a todo list
todo.push_back(MapPtrIdx);
} else {
*/
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
#if LLVM_VERSION_MAJOR >= 13
llvm::MaybeAlign(1),
@ -659,7 +643,6 @@ bool AFLCoverage::runOnModule(Module &M) {
*/
} else {
LoadInst *Counter = IRB.CreateLoad(MapPtrIdx);
Counter->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
@ -688,13 +671,12 @@ bool AFLCoverage::runOnModule(Module &M) {
auto cf = IRB.CreateICmpEQ(Incr, Zero);
auto carry = IRB.CreateZExt(cf, Int8Ty);
Incr = IRB.CreateAdd(Incr, carry);
}
IRB.CreateStore(Incr, MapPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
} /* non atomic case */
} /* non atomic case */
/* Update prev_loc history vector (by placing cur_loc at the head of the
vector and shuffle the other elements back by one) */
@ -703,7 +685,6 @@ bool AFLCoverage::runOnModule(Module &M) {
#ifdef HAVE_VECTOR_INTRINSICS
if (Ngram) {
Value *ShuffledPrevLoc = IRB.CreateShuffleVector(
PrevLoc, UndefValue::get(PrevLocTy), PrevLocShuffleMask);
Value *UpdatedPrevLoc = IRB.CreateInsertElement(
@ -713,24 +694,20 @@ bool AFLCoverage::runOnModule(Module &M) {
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
} else
#endif
{
Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
AFLPrevLoc);
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
}
// in CTX mode we have to restore the original context for the caller -
// she might be calling other functions which need the correct CTX.
// Currently this is only needed for the Ubuntu clang-6.0 bug
if (instrument_ctx && has_calls) {
Instruction *Inst = BB.getTerminator();
if (isa<ReturnInst>(Inst) || isa<ResumeInst>(Inst)) {
IRBuilder<> Post_IRB(Inst);
StoreInst *RestoreCtx;
@ -742,39 +719,37 @@ bool AFLCoverage::runOnModule(Module &M) {
RestoreCtx = Post_IRB.CreateStore(PrevCtx, AFLContext);
RestoreCtx->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
}
}
inst_blocks++;
}
}
if (DumpCFG) {
int fd;
if ((fd = open(DumpCFGPath.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0)
if ((fd = open(DumpCFGPath.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644)) <
0)
FATAL("Could not open/create CFG dump file.");
std::string cfg = "";
for (auto record = entry_bb.begin(); record != entry_bb.end(); record++) {
// Dump function BB entry points
cfg += formatv("$${0}+{1}\n", record->getFirst(), bb_to_cur_loc[record->getSecond()]);
cfg += formatv("$${0}+{1}\n", record->getFirst(),
bb_to_cur_loc[record->getSecond()]);
}
for (auto record = bb_to_cur_loc.begin(); record != bb_to_cur_loc.end(); record++) {
for (auto record = bb_to_cur_loc.begin(); record != bb_to_cur_loc.end();
record++) {
// Dump CFG information
auto current_bb = record->getFirst();
Function* calling_func = current_bb->getParent();
auto current_bb = record->getFirst();
Function *calling_func = current_bb->getParent();
if (calling_func) {
auto function_name = calling_func->getName().str();
cfg += formatv("%%{0}", function_name);
}
else
} else
cfg += "%%__";
auto current_cur_loc = record->getSecond();
cfg += formatv("+{0}\n", current_cur_loc);
for (auto bb_successor = succ_begin(current_bb);
bb_successor != succ_end(current_bb); bb_successor++) {
bb_successor != succ_end(current_bb); bb_successor++) {
cfg += formatv("->{0}\n", bb_to_cur_loc[*bb_successor]).str();
}
}
@ -804,14 +779,13 @@ bool AFLCoverage::runOnModule(Module &M) {
}
}*/
if (Debug) {
if (Debug) {
if (!inst_blocks)
fprintf(stderr, "No instrumentation targets found.\n");
else
fprintf(stderr, "Instrumented %d locations (ratio %u%%).\n", inst_blocks, (unsigned)InstRatio);
fprintf(stderr, "Instrumented %d locations (ratio %u%%).\n", inst_blocks,
(unsigned)InstRatio);
}
#ifdef USE_NEW_PM
@ -819,15 +793,12 @@ bool AFLCoverage::runOnModule(Module &M) {
#else
return true;
#endif
}
#ifndef USE_NEW_PM
static void registerAFLPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLCoverage());
}
static RegisterStandardPasses RegisterAFLPass(

View File

@ -64,12 +64,11 @@
#include <iostream>
#define FATAL(x...) \
do { \
\
fprintf(stderr, "FATAL: " x); \
exit(1); \
\
#define FATAL(x...) \
do { \
fprintf(stderr, "FATAL: " x); \
exit(1); \
\
} while (0)
using namespace llvm;
@ -79,7 +78,6 @@ namespace {
/* Function that we never instrument or analyze */
/* Note: this ignore check is also called in isInInstrumentList() */
bool isIgnoreFunction(const llvm::Function *F) {
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based
// fuzzing campaign installations, e.g. oss-fuzz
@ -117,9 +115,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
};
for (auto const &ignoreListFunc : ignoreList) {
if (F->getName().startswith(ignoreListFunc)) { return true; }
}
static constexpr const char *ignoreSubstringList[] = {
@ -131,67 +127,51 @@ bool isIgnoreFunction(const llvm::Function *F) {
};
for (auto const &ignoreListFunc : ignoreSubstringList) {
// hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
}
return false;
}
class AutoTokensPass : public ModulePass {
public:
static char ID;
AutoTokensPass() : ModulePass(ID) {
}
bool runOnModule(Module &M) override;
protected:
private:
std::vector<std::string> dictionary;
protected:
private:
std::vector<std::string> dictionary;
};
} // namespace
char AutoTokensPass::ID = 0;
void dict2file(int fd, uint8_t *mem, uint32_t len) {
uint32_t i, j, binary = 0;
char line[MAX_AUTO_EXTRA * 8], tmp[8];
uint32_t i, j, binary = 0;
char line[MAX_AUTO_EXTRA * 8], tmp[8];
strcpy(line, "\"");
j = 1;
for (i = 0; i < len; i++) {
if (isprint(mem[i]) && mem[i] != '\\' && mem[i] != '"') {
line[j++] = mem[i];
} else {
if (i + 1 != len || mem[i] != 0 || binary || len == 4 || len == 8) {
line[j] = 0;
sprintf(tmp, "\\x%02x", (uint8_t)mem[i]);
strcat(line, tmp);
j = strlen(line);
}
binary = 1;
}
}
line[j] = 0;
@ -199,15 +179,13 @@ void dict2file(int fd, uint8_t *mem, uint32_t len) {
if (write(fd, line, strlen(line)) <= 0)
FATAL("Could not write to dictionary file");
fsync(fd);
}
bool AutoTokensPass::runOnModule(Module &M) {
DenseMap<Value *, std::string *> valueMap;
char * ptr;
char *ptr;
int fd, found = 0;
bool use_file = true;
bool use_file = true;
/* Show a banner */
setvbuf(stdout, NULL, _IONBF, 0);
@ -215,22 +193,21 @@ bool AutoTokensPass::runOnModule(Module &M) {
ptr = getenv("AFL_LLVM_DICT2FILE");
if (!ptr || *ptr != '/') {
// fprintf(stderr, "AFL_LLVM_DICT2FILE is not set to an absolute path: %s\n", ptr);
// fprintf(stderr, "Writing tokens into libafl_tokens section\n");
// fprintf(stderr, "AFL_LLVM_DICT2FILE is not set to an absolute path:
// %s\n", ptr); fprintf(stderr, "Writing tokens into libafl_tokens
// section\n");
use_file = false;
}
if(use_file) {
if (use_file) {
if ((fd = open(ptr, O_WRONLY | O_APPEND | O_CREAT | O_DSYNC, 0644)) < 0)
FATAL("Could not open/create %s.", ptr);
}
/* Instrument all the things! */
for (auto &F : M) {
if (isIgnoreFunction(&F)) continue;
/* Some implementation notes.
@ -262,15 +239,12 @@ bool AutoTokensPass::runOnModule(Module &M) {
*/
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
CmpInst * cmpInst = nullptr;
CmpInst *cmpInst = nullptr;
if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
Value * op = cmpInst->getOperand(1);
Value *op = cmpInst->getOperand(1);
ConstantInt *ilen = dyn_cast<ConstantInt>(op);
/* We skip > 64 bit integers. why? first because their value is
@ -278,18 +252,15 @@ bool AutoTokensPass::runOnModule(Module &M) {
literals > 64 bit (as of llvm 12) */
if (ilen && ilen->uge(0xffffffffffffffff) == false) {
uint64_t val2 = 0, val = ilen->getZExtValue();
uint32_t len = 0;
if (val > 0x10000 && val < 0xffffffff) len = 4;
if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8;
if (len) {
auto c = cmpInst->getPredicate();
switch (c) {
case CmpInst::FCMP_OGT: // fall through
case CmpInst::FCMP_OLE: // fall through
case CmpInst::ICMP_SLE: // fall through
@ -298,10 +269,8 @@ bool AutoTokensPass::runOnModule(Module &M) {
// signed comparison and it is a negative constant
if ((len == 4 && (val & 80000000)) ||
(len == 8 && (val & 8000000000000000))) {
if ((val & 0xffff) != 1) val2 = val - 1;
break;
}
// fall through
@ -321,10 +290,8 @@ bool AutoTokensPass::runOnModule(Module &M) {
// signed comparison and it is a negative constant
if ((len == 4 && (val & 80000000)) ||
(len == 8 && (val & 8000000000000000))) {
if ((val & 0xffff) != 1) val2 = val - 1;
break;
}
// fall through
@ -338,37 +305,28 @@ bool AutoTokensPass::runOnModule(Module &M) {
default:
val2 = 0;
}
if(use_file) {
if (use_file) {
dict2file(fd, (uint8_t *)&val, len);
}
else{
} else {
dictionary.push_back(std::string((char *)&val, len));
}
found++;
if (val2) {
if(use_file) {
if (use_file) {
dict2file(fd, (uint8_t *)&val2, len);
}
else{
} else {
dictionary.push_back(std::string((char *)&val2, len));
}
found++;
}
}
}
}
if ((callInst = dyn_cast<CallInst>(&IN))) {
bool isStrcmp = true;
bool isMemcmp = true;
bool isStrncmp = true;
@ -448,138 +406,96 @@ bool AutoTokensPass::runOnModule(Module &M) {
getConstantStringInfo(Str1P, TmpStr);
if (TmpStr.empty()) {
HasStr1 = false;
} else {
HasStr1 = true;
Str1 = TmpStr.str();
}
bool HasStr2;
getConstantStringInfo(Str2P, TmpStr);
if (TmpStr.empty()) {
HasStr2 = false;
} else {
HasStr2 = true;
Str2 = TmpStr.str();
}
// we handle the 2nd parameter first because of llvm memcpy
if (!HasStr2) {
auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr2 = true;
Str2 = Array->getRawDataValues().str();
}
}
}
}
}
// for the internal memcpy routine we only care for the second
// parameter and are not reporting anything.
if (isIntMemcpy == true) {
if (HasStr2 == true) {
Value * op2 = callInst->getArgOperand(2);
Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = Str2.length();
uint64_t optLength = ilen->getZExtValue();
if (literalLength + 1 == optLength) {
Str2.append("\0", 1); // add null byte
}
if (optLength > Str2.length()) { optLength = Str2.length(); }
}
valueMap[Str1P] = new std::string(Str2);
continue;
}
continue;
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr2) {
std::string *strng = valueMap[Str2P];
if (strng && !strng->empty()) {
Str2 = *strng;
HasStr2 = true;
}
}
if (!HasStr1) {
auto Ptr = dyn_cast<ConstantExpr>(Str1P);
if (Ptr && Ptr->isGEPWithNoNotionalOverIndexing()) {
if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
if (Var->hasInitializer()) {
if (auto *Array =
dyn_cast<ConstantDataArray>(Var->getInitializer())) {
HasStr1 = true;
Str1 = Array->getRawDataValues().str();
}
}
}
}
}
// Neither a literal nor a global variable?
// maybe it is a local variable that we saved
if (!HasStr1) {
std::string *strng = valueMap[Str1P];
if (strng && !strng->empty()) {
Str1 = *strng;
HasStr1 = true;
}
}
/* handle cases of one string is const, one string is variable */
@ -597,12 +513,10 @@ bool AutoTokensPass::runOnModule(Module &M) {
if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
if (isMemcmp || isStrncmp || isStrncasecmp) {
Value * op2 = callInst->getArgOperand(2);
Value *op2 = callInst->getArgOperand(2);
ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
if (ilen) {
uint64_t literalLength = optLen;
optLen = ilen->getZExtValue();
if (optLen > thestring.length()) { optLen = thestring.length(); }
@ -610,33 +524,24 @@ bool AutoTokensPass::runOnModule(Module &M) {
if (literalLength + 1 == optLen) { // add null byte
thestring.append("\0", 1);
addedNull = true;
}
}
}
// add null byte if this is a string compare function and a null
// was not already added
if (!isMemcmp) {
if (addedNull == false && thestring[optLen - 1] != '\0') {
thestring.append("\0", 1); // add null byte
optLen++;
}
if (!isStdString) {
// ensure we do not have garbage
size_t offset = thestring.find('\0', 0);
if (offset + 1 < optLen) optLen = offset + 1;
thestring = thestring.substr(0, optLen);
}
}
// we take the longer string, even if the compare was to a
@ -650,85 +555,70 @@ bool AutoTokensPass::runOnModule(Module &M) {
ptr = (char *)thestring.c_str();
if(use_file){
if (use_file) {
dict2file(fd, (uint8_t *)ptr, optLen);
}
else{
} else {
dictionary.push_back(thestring.substr(0, optLen));
}
found++;
}
}
}
}
if(use_file){
if (use_file) {
close(fd);
return true;
}
LLVMContext &Ctx = M.getContext();
if (dictionary.size()) {
size_t memlen = 0, count = 0, offset = 0;
size_t memlen = 0, count = 0, offset = 0;
// sort and unique the dictionary
std::sort(dictionary.begin(), dictionary.end());
auto last = std::unique(dictionary.begin(), dictionary.end());
dictionary.erase(last, dictionary.end());
// sort and unique the dictionary
std::sort(dictionary.begin(), dictionary.end());
auto last = std::unique(dictionary.begin(), dictionary.end());
dictionary.erase(last, dictionary.end());
for (auto token : dictionary) {
memlen += token.length();
count++;
}
for (auto token : dictionary) {
auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
memlen += token.length();
count = 0;
for (auto token : dictionary) {
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
// This lenght is guranteed to be < MAX_AUTO_EXTRA
ptrhld.get()[offset++] = (uint8_t)token.length();
memcpy(ptrhld.get() + offset, token.c_str(), token.length());
offset += token.length();
count++;
}
if (count) {
auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
count = 0;
for (auto token : dictionary) {
if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
// This lenght is guranteed to be < MAX_AUTO_EXTRA
ptrhld.get()[offset++] = (uint8_t)token.length();
memcpy(ptrhld.get() + offset, token.c_str(), token.length());
offset += token.length();
count++;
}
}
// Type
ArrayType* arrayTy = ArrayType::get(IntegerType::get(Ctx, 8), offset);
// The actual dict
GlobalVariable *dict = new GlobalVariable(M, arrayTy, true, GlobalVariable::ExternalLinkage, ConstantDataArray::get(Ctx, *(new ArrayRef<char>(ptrhld.get(), offset))), "libafl_dictionary_" + M.getName());
dict->setSection("libafl_token");
}
}
// Type
ArrayType *arrayTy = ArrayType::get(IntegerType::get(Ctx, 8), offset);
// The actual dict
GlobalVariable *dict = new GlobalVariable(
M, arrayTy, true, GlobalVariable::ExternalLinkage,
ConstantDataArray::get(Ctx, *(new ArrayRef<char>(ptrhld.get(), offset))),
"libafl_dictionary_" + M.getName());
dict->setSection("libafl_token");
return true;
}
static void registerAutoTokensPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
legacy::PassManagerBase &PM) {
PM.add(new AutoTokensPass());
}
static RegisterPass<AutoTokensPass> X("autotokens",
"autotokens instrumentation pass",
false, false);
"autotokens instrumentation pass", false,
false);
static RegisterStandardPasses RegisterAutoTokensPass(
PassManagerBuilder::EP_OptimizerLast, registerAutoTokensPass);

View File

@ -55,7 +55,6 @@ namespace {
/* Function that we never instrument or analyze */
/* Note: this ignore check is also called in isInInstrumentList() */
bool isIgnoreFunction(const llvm::Function *F) {
// Starting from "LLVMFuzzer" these are functions used in libfuzzer based
// fuzzing campaign installations, e.g. oss-fuzz
@ -93,9 +92,7 @@ bool isIgnoreFunction(const llvm::Function *F) {
};
for (auto const &ignoreListFunc : ignoreList) {
if (F->getName().startswith(ignoreListFunc)) { return true; }
}
static constexpr const char *ignoreSubstringList[] = {
@ -107,38 +104,32 @@ bool isIgnoreFunction(const llvm::Function *F) {
};
for (auto const &ignoreListFunc : ignoreSubstringList) {
// hexcoder: F->getName().contains() not avaiilable in llvm 3.8.0
if (StringRef::npos != F->getName().find(ignoreListFunc)) { return true; }
}
return false;
}
class CmpLogRoutines : public ModulePass {
public:
static char ID;
CmpLogRoutines() : ModulePass(ID) {}
CmpLogRoutines() : ModulePass(ID) {
}
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR < 4
const char *getPassName() const override {
#else
StringRef getPassName() const override {
#endif
return "cmplog routines";
}
private:
bool hookRtns(Module &M);
};
} // namespace
@ -146,9 +137,8 @@ class CmpLogRoutines : public ModulePass {
char CmpLogRoutines::ID = 0;
bool CmpLogRoutines::hookRtns(Module &M) {
std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC;
LLVMContext & C = M.getContext();
LLVMContext &C = M.getContext();
Type *VoidTy = Type::getVoidTy(C);
// PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
@ -246,17 +236,13 @@ bool CmpLogRoutines::hookRtns(Module &M) {
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
if (isIgnoreFunction(&F)) continue;
for (auto &BB : F) {
for (auto &IN : BB) {
CallInst *callInst = nullptr;
if ((callInst = dyn_cast<CallInst>(&IN))) {
Function *Callee = callInst->getCalledFunction();
if (!Callee) continue;
if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
@ -316,9 +302,7 @@ bool CmpLogRoutines::hookRtns(Module &M) {
if (isGccStdStringCString || isGccStdStringStdString ||
isLlvmStdStringStdString || isLlvmStdStringCString) {
isPtrRtn = false;
}
if (isPtrRtn) { calls.push_back(callInst); }
@ -326,13 +310,9 @@ bool CmpLogRoutines::hookRtns(Module &M) {
if (isGccStdStringCString) { gccStdC.push_back(callInst); }
if (isLlvmStdStringStdString) { llvmStdStd.push_back(callInst); }
if (isLlvmStdStringCString) { llvmStdC.push_back(callInst); }
}
}
}
}
if (!calls.size() && !gccStdStd.size() && !gccStdC.size() &&
@ -340,119 +320,104 @@ bool CmpLogRoutines::hookRtns(Module &M) {
return false;
for (auto &callInst : calls) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
IRB.CreateCall(cmplogHookFn, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : gccStdStd) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
IRB.CreateCall(cmplogGccStdStd, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : gccStdC) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
IRB.CreateCall(cmplogGccStdC, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : llvmStdStd) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
IRB.CreateCall(cmplogLlvmStdStd, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
for (auto &callInst : llvmStdC) {
Value *v1P = callInst->getArgOperand(0), *v2P = callInst->getArgOperand(1);
IRBuilder<> IRB(callInst->getParent());
IRB.SetInsertPoint(callInst);
std::vector<Value *> args;
Value * v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value * v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
Value *v1Pcasted = IRB.CreatePointerCast(v1P, i8PtrTy);
Value *v2Pcasted = IRB.CreatePointerCast(v2P, i8PtrTy);
args.push_back(v1Pcasted);
args.push_back(v2Pcasted);
IRB.CreateCall(cmplogLlvmStdC, args);
// errs() << callInst->getCalledFunction()->getName() << "\n";
}
return true;
}
bool CmpLogRoutines::runOnModule(Module &M) {
hookRtns(M);
verifyModule(M);
return true;
}
static void registerCmpLogRoutinesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmpLogRoutines();
PM.add(p);
}
static RegisterStandardPasses RegisterCmpLogRoutinesPass(
@ -466,4 +431,3 @@ static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmpLogRoutinesPass);
#endif

View File

@ -54,59 +54,52 @@ typedef uint32_t prev_loc_t;
#define MAP_SIZE LIBAFL_ACCOUNTING_MAP_SIZE
#define SECURITY_SENSITIVE_FUNCS(CF) static CF securitySensitiveFunctions[] = {\
CF("memcpy"), \
CF("strlen"), \
CF("ReadImage"), \
CF("memmove"), \
CF("free"), \
CF("memset"), \
CF("delete"), \
CF("memcmp"), \
CF("getString"), \
CF("vsprintf"), \
CF("GET_COLOR"), \
CF("read"), \
CF("load_bmp"), \
CF("huffcode"), \
CF("strcmp"), \
CF("new"), \
CF("getName"), \
CF("strncat"), \
CF("png_load"), \
};
#define SECURITY_SENSITIVE_FUNCS(CF) \
static CF securitySensitiveFunctions[] = { \
CF("memcpy"), CF("strlen"), CF("ReadImage"), CF("memmove"), \
CF("free"), CF("memset"), CF("delete"), CF("memcmp"), \
CF("getString"), CF("vsprintf"), CF("GET_COLOR"), CF("read"), \
CF("load_bmp"), CF("huffcode"), CF("strcmp"), CF("new"), \
CF("getName"), CF("strncat"), CF("png_load"), \
};
using namespace llvm;
enum AccountingGranularity {
BB_GRAN,
FUNC_GRAN,
// LOOP,
UKNOWN_GRAN
BB_GRAN,
FUNC_GRAN,
// LOOP,
UKNOWN_GRAN
};
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false), cl::NotHidden);
static cl::opt<std::string> GranularityStr("granularity", cl::desc("Granularity of accounting (BB, FUNC)"), cl::init(std::string("BB")), cl::NotHidden);
static cl::opt<uint32_t> InstRatio("inst_ratio", cl::desc("Instrumentation ratio in percentage"), cl::init(100), cl::NotHidden);
static cl::opt<bool> ThreadSafe("thread_safe", cl::desc("Use the thread safe instrumentation"), cl::init(false), cl::NotHidden);
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false),
cl::NotHidden);
static cl::opt<std::string> GranularityStr(
"granularity", cl::desc("Granularity of accounting (BB, FUNC)"),
cl::init(std::string("BB")), cl::NotHidden);
static cl::opt<uint32_t> InstRatio(
"inst_ratio", cl::desc("Instrumentation ratio in percentage"),
cl::init(100), cl::NotHidden);
static cl::opt<bool> ThreadSafe("thread_safe",
cl::desc("Use the thread safe instrumentation"),
cl::init(false), cl::NotHidden);
namespace {
SECURITY_SENSITIVE_FUNCS(StringRef)
bool isSecuritySensitiveFunction(Function* F) {
if (!F) return 0;
auto func_name = F->getName();
for (auto name : securitySensitiveFunctions) {
if (func_name.contains(name)) {
if (Debug)
fprintf(stderr, "Counted %s as security sensitive", func_name.str().c_str());
return 1;
}
bool isSecuritySensitiveFunction(Function *F) {
if (!F) return 0;
auto func_name = F->getName();
for (auto name : securitySensitiveFunctions) {
if (func_name.contains(name)) {
if (Debug)
fprintf(stderr, "Counted %s as security sensitive",
func_name.str().c_str());
return 1;
}
return 0;
}
return 0;
}
#ifdef USE_NEW_PM
@ -120,11 +113,10 @@ class AFLCoverage : public ModulePass {
AFLCoverage() : ModulePass(ID) {
#endif
granularity = StringSwitch<AccountingGranularity>(GranularityStr)
.Case("BB", BB_GRAN)
.Case("FUNC", FUNC_GRAN)
.Default(UKNOWN_GRAN);
.Case("BB", BB_GRAN)
.Case("FUNC", FUNC_GRAN)
.Default(UKNOWN_GRAN);
// initInstrumentList();
}
#ifdef USE_NEW_PM
@ -134,10 +126,9 @@ class AFLCoverage : public ModulePass {
#endif
protected:
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1;
AccountingGranularity granularity;
};
} // namespace
@ -145,33 +136,30 @@ class AFLCoverage : public ModulePass {
#ifdef USE_NEW_PM
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
return {
LLVM_PLUGIN_API_VERSION, "AFLCoverageAccounting", "v0.1",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if 1
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(AFLCoverage());
}
);
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback(
[](StringRef Name, ModulePassManager &MPM, ArrayRef<PipelineElement>) {
if ( Name == "AFLCoverageAccounting" ) {
MPM.addPass(AFLCoverage());
return true;
} else {
return false;
}
}
);
#endif
}
};
return {LLVM_PLUGIN_API_VERSION, "AFLCoverageAccounting", "v0.1",
/* lambda to insert our pass into the pass pipeline. */
[](PassBuilder &PB) {
#if 1
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(AFLCoverage());
});
/* TODO LTO registration */
#else
using PipelineElement = typename PassBuilder::PipelineElement;
PB.registerPipelineParsingCallback([](StringRef Name,
ModulePassManager &MPM,
ArrayRef<PipelineElement>) {
if (Name == "AFLCoverageAccounting") {
MPM.addPass(AFLCoverage());
return true;
} else {
return false;
}
});
#endif
}};
}
#else
@ -187,7 +175,7 @@ bool AFLCoverage::runOnModule(Module &M) {
LLVMContext &C = M.getContext();
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
uint32_t rand_seed;
uint32_t rand_seed;
unsigned int cur_loc = 0;
#ifdef USE_NEW_PM
@ -206,19 +194,19 @@ bool AFLCoverage::runOnModule(Module &M) {
/* Get globals for the SHM region and the previous location. Note that
__afl_acc_prev_loc is thread-local. */
GlobalVariable *AFLMemOpPtr =
new GlobalVariable(M, PointerType::get(Int32Ty, 0), false,
GlobalValue::ExternalLinkage, 0, "__afl_acc_memop_ptr");
GlobalVariable *AFLMemOpPtr = new GlobalVariable(
M, PointerType::get(Int32Ty, 0), false, GlobalValue::ExternalLinkage, 0,
"__afl_acc_memop_ptr");
GlobalVariable *AFLPrevLoc;
#if defined(__ANDROID__) || defined(__HAIKU__)
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc");
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc");
#else
AFLPrevLoc = new GlobalVariable(
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc", 0,
GlobalVariable::GeneralDynamicTLSModel, 0, false);
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc",
0, GlobalVariable::GeneralDynamicTLSModel, 0, false);
#endif
/* Instrument all the things! */
@ -227,7 +215,6 @@ bool AFLCoverage::runOnModule(Module &M) {
// scanForDangerousFunctions(&M);
for (auto &F : M) {
int has_calls = 0;
if (Debug)
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
@ -239,7 +226,6 @@ bool AFLCoverage::runOnModule(Module &M) {
std::list<Value *> todo;
for (auto &BB : F) {
BasicBlock::iterator IP = BB.getFirstInsertionPt();
IRBuilder<> IRB(&(*IP));
@ -250,8 +236,7 @@ bool AFLCoverage::runOnModule(Module &M) {
for (auto &I : BB) {
switch (granularity) {
case BB_GRAN:
if (I.mayReadFromMemory() || I.mayWriteToMemory())
++MemCnt;
if (I.mayReadFromMemory() || I.mayWriteToMemory()) ++MemCnt;
break;
case FUNC_GRAN:
if (auto *C = dyn_cast<CallInst>(&I)) {
@ -275,36 +260,37 @@ bool AFLCoverage::runOnModule(Module &M) {
/* Load SHM pointer */
LoadInst *MemReadPtr = IRB.CreateLoad(AFLMemOpPtr);
MemReadPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MemReadPtrIdx = IRB.CreateGEP(MemReadPtr, IRB.CreateXor(PrevLoc, CurLoc));
MemReadPtr->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *MemReadPtrIdx =
IRB.CreateGEP(MemReadPtr, IRB.CreateXor(PrevLoc, CurLoc));
/* Update bitmap */
LoadInst *MemReadCount = IRB.CreateLoad(MemReadPtrIdx);
MemReadCount->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
Value *MemReadIncr = IRB.CreateAdd(MemReadCount, ConstantInt::get(Int32Ty, MemCnt));
MemReadCount->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));
Value *MemReadIncr =
IRB.CreateAdd(MemReadCount, ConstantInt::get(Int32Ty, MemCnt));
IRB.CreateStore(MemReadIncr, MemReadPtrIdx)
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
/* Update prev_loc */
StoreInst * Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
AFLPrevLoc);
StoreInst *Store =
IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1), AFLPrevLoc);
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
inst_blocks++;
}
}
if (Debug) {
if (Debug) {
if (!inst_blocks)
fprintf(stderr, "No instrumentation targets found.\n");
else
fprintf(stderr, "Instrumented %d locations (ratio %u%%).\n", inst_blocks, (unsigned)InstRatio);
fprintf(stderr, "Instrumented %d locations (ratio %u%%).\n", inst_blocks,
(unsigned)InstRatio);
}
#ifdef USE_NEW_PM
@ -312,15 +298,12 @@ bool AFLCoverage::runOnModule(Module &M) {
#else
return true;
#endif
}
#ifndef USE_NEW_PM
static void registerAFLPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
PM.add(new AFLCoverage());
}
static RegisterStandardPasses RegisterAFLPass(