Recover useful CmpLog updates from #1630 (#1684)

* add

* ci

* wip

* make type name more clear

* last

* add

* more fix

* chg

* fmt

* save changes

* fix_handler

* cfg

* win

* fix

* toml

* f

* more

* fix all the stuff

* fix

* revert fuzzers/fuzzbench to origin/main
This commit is contained in:
Dongjia "toka" Zhang 2024-01-03 23:44:32 +01:00 committed by GitHub
parent 9b2a17896f
commit 75fcd47044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 545 additions and 544 deletions

View File

@ -715,8 +715,8 @@ impl AFLppRedQueen {
};
// Try arith
let diff: i64 = (pattern - b_val) as i64;
let new_diff: i64 = (another_pattern - o_b_val) as i64;
let diff = pattern as i64 - b_val as i64;
let new_diff = another_pattern as i64 - o_b_val as i64;
if diff == new_diff && diff != 0 {
let new_repl: u64 = (repl as i64 - diff) as u64;

View File

@ -408,7 +408,6 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
"autotokens-pass.cc",
"coverage-accounting-pass.cc",
"cmplog-instructions-pass.cc",
"cmplog-switches-pass.cc",
] {
build_pass(
bindir_path,

View File

@ -44,9 +44,6 @@ pub enum LLVMPasses {
#[cfg(unix)]
/// The CmpLog Instruction pass
CmpLogInstructions,
#[cfg(unix)]
/// The CmpLog Switch pass
CmpLogSwitches,
}
impl LLVMPasses {
@ -69,9 +66,6 @@ impl LLVMPasses {
#[cfg(unix)]
LLVMPasses::CmpLogInstructions => PathBuf::from(env!("OUT_DIR"))
.join(format!("cmplog-instructions-pass.{}", dll_extension())),
#[cfg(unix)]
LLVMPasses::CmpLogSwitches => PathBuf::from(env!("OUT_DIR"))
.join(format!("cmplog-switches-pass.{}", dll_extension())),
}
}
}

View File

@ -98,7 +98,11 @@ llvmGetPassPluginInfo() {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
#if LLVM_VERSION_MAJOR >= 16
PB.registerOptimizerEarlyEPCallback(
#else
PB.registerOptimizerLastEPCallback(
#endif
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(CmpLogInstructions());
});
@ -121,6 +125,7 @@ Iterator Unique(Iterator first, Iterator last) {
bool CmpLogInstructions::hookInstrs(Module &M) {
std::vector<Instruction *> icomps;
std::vector<SwitchInst *> switches;
LLVMContext &C = M.getContext();
Type *VoidTy = Type::getVoidTy(C);
@ -202,8 +207,16 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
}
}
}
for (auto &BB : F) {
SwitchInst *switchInst = nullptr;
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); }
}
}
}
switches.erase(Unique(switches.begin(), switches.end()), switches.end());
if (icomps.size()) {
// if (!be_quiet) errs() << "Hooking " << icomps.size() <<
// " cmp instructions\n";
@ -500,11 +513,114 @@ bool CmpLogInstructions::hookInstrs(Module &M) {
}
}
if (icomps.size()) {
return true;
} else {
return false;
if (switches.size()) {
for (auto &SI : switches) {
Value *Val = SI->getCondition();
unsigned int max_size = Val->getType()->getIntegerBitWidth();
unsigned int cast_size;
unsigned char do_cast = 0;
if (!SI->getNumCases() || max_size < 16) {
// skipping trivial switch
continue;
}
if (max_size % 8) {
max_size = (((max_size / 8) + 1) * 8);
do_cast = 1;
}
if (max_size > 128) {
// can't handle this
max_size = 128;
do_cast = 1;
}
IRBuilder<> IRB(SI->getParent());
IRB.SetInsertPoint(SI);
switch (max_size) {
case 8:
case 16:
case 32:
case 64:
case 128:
cast_size = max_size;
break;
default:
cast_size = 128;
do_cast = 1;
}
// The predicate of the switch clause
Value *CompareTo = Val;
if (do_cast) {
CompareTo =
IRB.CreateIntCast(CompareTo, IntegerType::get(C, cast_size), false);
}
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
++i) {
// Who uses LLVM Major < 5?? :p
ConstantInt *cint = i->getCaseValue();
if (cint) {
std::vector<Value *> args;
args.push_back(CompareTo);
Value *new_param = cint;
if (do_cast) {
new_param =
IRB.CreateIntCast(cint, IntegerType::get(C, cast_size), false);
}
if (new_param) {
args.push_back(new_param);
if (CmplogExtended) {
ConstantInt *attribute = ConstantInt::get(Int8Ty, 1);
args.push_back(attribute);
}
if (cast_size != max_size) {
// not 8, 16, 32, 64, 128.
ConstantInt *bitsize =
ConstantInt::get(Int8Ty, (max_size / 8) - 1);
args.push_back(bitsize); // we have the arg for size in hookinsN
}
switch (cast_size) {
case 8:
IRB.CreateCall(cmplogHookIns1, args);
break;
case 16:
IRB.CreateCall(cmplogHookIns2, args);
break;
case 32:
IRB.CreateCall(cmplogHookIns4, args);
break;
case 64:
IRB.CreateCall(cmplogHookIns8, args);
break;
case 128:
#ifdef WORD_SIZE_64
if (max_size == 128) {
IRB.CreateCall(cmplogHookIns16, args);
} else {
IRB.CreateCall(cmplogHookInsN, args);
}
#endif
break;
default:
break;
}
}
}
}
}
}
return true;
}
#if USE_NEW_PM

View File

@ -50,7 +50,9 @@
#include <set>
using namespace llvm;
static cl::opt<bool> CmplogExtended("cmplog_routines_extended",
cl::desc("Uses extended header"),
cl::init(false), cl::NotHidden);
namespace {
#if USE_NEW_PM
@ -114,150 +116,85 @@ bool CmpLogRoutines::hookRtns(Module &M) {
// PointerType *VoidPtrTy = PointerType::get(VoidTy, 0);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
PointerType *i8PtrTy = PointerType::get(Int8Ty, 0);
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c = M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogHookFn = cast<Function>(c);
#else
FunctionCallee cmplogHookFn = c;
#endif
FunctionCallee cmplogHookFn;
FunctionCallee cmplogLlvmStdStd;
FunctionCallee cmplogLlvmStdC;
FunctionCallee cmplogGccStdStd;
FunctionCallee cmplogGccStdC;
FunctionCallee cmplogHookFnN;
FunctionCallee cmplogHookFnStrN;
FunctionCallee cmplogHookFnStr;
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c1 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring",
VoidTy, i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogLlvmStdStd = cast<Function>(c1);
#else
FunctionCallee cmplogLlvmStdStd = c1;
#endif
if (CmplogExtended) {
cmplogHookFn = M.getOrInsertFunction("__cmplog_rtn_hook_extended", VoidTy,
i8PtrTy, i8PtrTy);
} else {
cmplogHookFn =
M.getOrInsertFunction("__cmplog_rtn_hook", VoidTy, i8PtrTy, i8PtrTy);
}
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c2 = M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogLlvmStdC = cast<Function>(c2);
#else
FunctionCallee cmplogLlvmStdC = c2;
#endif
if (CmplogExtended) {
cmplogLlvmStdStd =
M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_stdstring_extended",
VoidTy, i8PtrTy, i8PtrTy);
} else {
cmplogLlvmStdStd = M.getOrInsertFunction(
"__cmplog_rtn_llvm_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
}
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c3 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogGccStdStd = cast<Function>(c3);
#else
FunctionCallee cmplogGccStdStd = c3;
#endif
if (CmplogExtended) {
cmplogLlvmStdC =
M.getOrInsertFunction("__cmplog_rtn_llvm_stdstring_cstring_extended",
VoidTy, i8PtrTy, i8PtrTy);
} else {
cmplogLlvmStdC = M.getOrInsertFunction(
"__cmplog_rtn_llvm_stdstring_cstring", VoidTy, i8PtrTy, i8PtrTy);
}
#if LLVM_VERSION_MAJOR < 9
Constant *
#else
FunctionCallee
#endif
c4 = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring", VoidTy,
i8PtrTy, i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR < 9
Function *cmplogGccStdC = cast<Function>(c4);
#else
FunctionCallee cmplogGccStdC = c4;
#endif
if (CmplogExtended) {
cmplogGccStdStd =
M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_stdstring_extended",
VoidTy, i8PtrTy, i8PtrTy);
} else {
cmplogGccStdStd = M.getOrInsertFunction(
"__cmplog_rtn_gcc_stdstring_stdstring", VoidTy, i8PtrTy, i8PtrTy);
}
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c5 = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnN = c5;
#else
Function *cmplogHookFnN = cast<Function>(c5);
#endif
if (CmplogExtended) {
cmplogGccStdC =
M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring_extended",
VoidTy, i8PtrTy, i8PtrTy);
} else {
cmplogGccStdC = M.getOrInsertFunction("__cmplog_rtn_gcc_stdstring_cstring",
VoidTy, i8PtrTy, i8PtrTy);
}
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c6 = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy, i8PtrTy,
i8PtrTy, Int64Ty
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStrN = c6;
#else
Function *cmplogHookFnStrN = cast<Function>(c6);
#endif
if (CmplogExtended) {
cmplogHookFnN = M.getOrInsertFunction("__cmplog_rtn_hook_n_extended",
VoidTy, i8PtrTy, i8PtrTy, Int64Ty);
} else {
cmplogHookFnN = M.getOrInsertFunction("__cmplog_rtn_hook_n", VoidTy,
i8PtrTy, i8PtrTy, Int64Ty);
}
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee
#else
Constant *
#endif
c7 = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy, i8PtrTy,
i8PtrTy
#if LLVM_VERSION_MAJOR < 5
,
NULL
#endif
);
#if LLVM_VERSION_MAJOR >= 9
FunctionCallee cmplogHookFnStr = c7;
#else
Function *cmplogHookFnStr = cast<Function>(c7);
#endif
if (CmplogExtended) {
cmplogHookFnStrN = M.getOrInsertFunction("__cmplog_rtn_hook_strn_extended",
VoidTy, i8PtrTy, i8PtrTy, Int64Ty);
} else {
cmplogHookFnStrN = M.getOrInsertFunction("__cmplog_rtn_hook_strn", VoidTy,
i8PtrTy, i8PtrTy, Int64Ty);
}
if (CmplogExtended) {
cmplogHookFnStr = M.getOrInsertFunction("__cmplog_rtn_hook_str_extended",
VoidTy, i8PtrTy, i8PtrTy);
} else {
cmplogHookFnStr = M.getOrInsertFunction("__cmplog_rtn_hook_str", VoidTy,
i8PtrTy, i8PtrTy);
}
/* iterate over all functions, bbs and instruction and add suitable calls */
for (auto &F : M) {
@ -613,4 +550,4 @@ static RegisterStandardPasses RegisterCmpLogRoutinesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmpLogRoutinesPass);
#endif
#endif

View File

@ -1,327 +0,0 @@
/*
american fuzzy lop++ - LLVM CmpLog instrumentation
--------------------------------------------------
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2015, 2016 Google Inc. All rights reserved.
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
#include <list>
#include <string>
#include <fstream>
#include "common-llvm.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Pass.h"
#include "llvm/Analysis/ValueTracking.h"
#if LLVM_VERSION_MAJOR > 3 || \
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
#include "llvm/IR/Verifier.h"
#include "llvm/IR/DebugInfo.h"
#else
#include "llvm/Analysis/Verifier.h"
#include "llvm/DebugInfo.h"
#define nullptr 0
#endif
#include <set>
using namespace llvm;
static cl::opt<bool> CmplogExtended("cmplog_switches_extended",
cl::desc("Uses extended header"),
cl::init(false), cl::NotHidden);
namespace {
#if USE_NEW_PM
class CmpLogSwitches : public PassInfoMixin<CmpLogSwitches> {
public:
CmpLogSwitches() {
#else
class CmpLogSwitches : public ModulePass {
public:
static char ID;
CmpLogSwitches() : ModulePass(ID) {
#endif
}
#if USE_NEW_PM
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
#else
bool runOnModule(Module &M) override;
#if LLVM_VERSION_MAJOR < 4
const char *getPassName() const override {
#else
StringRef getPassName() const override {
#endif
return "cmplog switches";
}
#endif
private:
bool hookInstrs(Module &M);
};
} // namespace
#if USE_NEW_PM
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {
return {LLVM_PLUGIN_API_VERSION, "CmpLogSwitches", "v0.1",
[](PassBuilder &PB) {
#if LLVM_VERSION_MAJOR <= 13
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
#endif
PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {
MPM.addPass(CmpLogSwitches());
});
}};
}
#else
char CmpLogSwitches::ID = 0;
#endif
template <class Iterator>
Iterator Unique(Iterator first, Iterator last) {
while (first != last) {
Iterator next(first);
last = std::remove(++next, last, *first);
first = next;
}
return last;
}
bool CmpLogSwitches::hookInstrs(Module &M) {
std::vector<SwitchInst *> switches;
LLVMContext &C = M.getContext();
Type *VoidTy = Type::getVoidTy(C);
IntegerType *Int8Ty = IntegerType::getInt8Ty(C);
IntegerType *Int16Ty = IntegerType::getInt16Ty(C);
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
FunctionCallee cmplogHookIns1;
FunctionCallee cmplogHookIns2;
FunctionCallee cmplogHookIns4;
FunctionCallee cmplogHookIns8;
if (CmplogExtended) {
cmplogHookIns1 = M.getOrInsertFunction("__cmplog_ins_hook1_extended",
VoidTy, Int8Ty, Int8Ty, Int8Ty);
} else {
cmplogHookIns1 = M.getOrInsertFunction("__cmplog_ins_hook1", VoidTy, Int8Ty,
Int8Ty, Int8Ty);
}
if (CmplogExtended) {
cmplogHookIns2 = M.getOrInsertFunction("__cmplog_ins_hook2_extended",
VoidTy, Int16Ty, Int16Ty, Int8Ty);
} else {
cmplogHookIns2 = M.getOrInsertFunction("__cmplog_ins_hook2", VoidTy,
Int16Ty, Int16Ty, Int8Ty);
}
if (CmplogExtended) {
cmplogHookIns4 = M.getOrInsertFunction("__cmplog_ins_hook4_extended",
VoidTy, Int32Ty, Int32Ty, Int8Ty);
} else {
cmplogHookIns4 = M.getOrInsertFunction("__cmplog_ins_hook4", VoidTy,
Int32Ty, Int32Ty, Int8Ty);
}
if (CmplogExtended) {
cmplogHookIns8 = M.getOrInsertFunction("__cmplog_ins_hook8_extended",
VoidTy, Int64Ty, Int64Ty, Int8Ty);
} else {
cmplogHookIns8 = M.getOrInsertFunction("__cmplog_ins_hook8", VoidTy,
Int64Ty, Int64Ty, Int8Ty);
}
for (auto &F : M) {
if (isIgnoreFunction(&F)) { continue; }
for (auto &BB : F) {
SwitchInst *switchInst = nullptr;
if ((switchInst = dyn_cast<SwitchInst>(BB.getTerminator()))) {
if (switchInst->getNumCases() > 1) { switches.push_back(switchInst); }
}
}
}
switches.erase(Unique(switches.begin(), switches.end()), switches.end());
if (switches.size()) {
for (auto &SI : switches) {
Value *Val = SI->getCondition();
unsigned int max_size = Val->getType()->getIntegerBitWidth();
unsigned int cast_size;
unsigned char do_cast = 0;
if (!SI->getNumCases() || max_size < 16) {
// skipping trivial switch
continue;
}
if (max_size % 8) {
max_size = (((max_size / 8) + 1) * 8);
do_cast = 1;
}
if (max_size > 128) {
// can't handle this
max_size = 128;
do_cast = 1;
}
IRBuilder<> IRB(SI->getParent());
IRB.SetInsertPoint(SI);
switch (max_size) {
case 8:
case 16:
case 32:
case 64:
case 128:
cast_size = max_size;
break;
default:
cast_size = 128;
do_cast = 1;
}
// The predicate of the switch clause
Value *CompareTo = Val;
if (do_cast) {
CompareTo =
IRB.CreateIntCast(CompareTo, IntegerType::get(C, cast_size), false);
}
for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e;
++i) {
// Who uses LLVM Major < 5?? :p
ConstantInt *cint = i->getCaseValue();
if (cint) {
std::vector<Value *> args;
args.push_back(CompareTo);
Value *new_param = cint;
if (do_cast) {
new_param =
IRB.CreateIntCast(cint, IntegerType::get(C, cast_size), false);
}
if (new_param) {
args.push_back(new_param);
if (CmplogExtended) {
ConstantInt *attribute = ConstantInt::get(Int8Ty, 1);
args.push_back(attribute);
}
if (cast_size != max_size) {
// not 8, 16, 32, 64, 128.
ConstantInt *bitsize =
ConstantInt::get(Int8Ty, (max_size / 8) - 1);
args.push_back(bitsize); // we have the arg for size in hookinsN
}
switch (cast_size) {
case 8:
IRB.CreateCall(cmplogHookIns1, args);
break;
case 16:
IRB.CreateCall(cmplogHookIns2, args);
break;
case 32:
IRB.CreateCall(cmplogHookIns4, args);
break;
case 64:
IRB.CreateCall(cmplogHookIns8, args);
break;
case 128:
#ifdef WORD_SIZE_64
if (max_size == 128) {
IRB.CreateCall(cmplogHookIns16, args);
} else {
IRB.CreateCall(cmplogHookInsN, args);
}
#endif
break;
default:
break;
}
}
}
}
}
}
}
#if USE_NEW_PM
PreservedAnalyses CmpLogSwitches::run(Module &M, ModuleAnalysisManager &MAM) {
#else
bool CmpLogSwitches::runOnModule(Module &M) {
#endif
hookInstrs(M);
#if USE_NEW_PM
auto PA = PreservedAnalyses::all();
#endif
verifyModule(M);
#if USE_NEW_PM
return PA;
#else
return true;
#endif
}
#if USE_NEW_PM
#else
static void registerCmpLogSwitchesPass(const PassManagerBuilder &,
legacy::PassManagerBase &PM) {
auto p = new CmpLogSwitches();
PM.add(p);
}
static RegisterStandardPasses RegisterCmpLogSwitchesPass(
PassManagerBuilder::EP_OptimizerLast, registerCmpLogSwitchesPass);
static RegisterStandardPasses RegisterCmpLogSwitchesPass0(
PassManagerBuilder::EP_EnabledOnOptLevel0, registerCmpLogSwitchesPass);
static RegisterStandardPasses RegisterCmpLogSwitchesPassLTO(
PassManagerBuilder::EP_FullLinkTimeOptimizationLast,
registerCmpLogSwitchesPass);
#endif

View File

@ -56,7 +56,7 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2) {
(void)arg2;
}
#if !defined(_WIN32) && defined(__SIZEOF_INT128__)
#ifndef _WIN32
void __cmplog_ins_hook16_extended(uint128_t arg1, uint128_t arg2,
uint8_t attr) {
(void)attr;
@ -86,6 +86,10 @@ void __cmplog_rtn_hook(uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr1;
(void)ptr2;
}
void __cmplog_rtn_hook_extended(uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr1;
(void)ptr2;
}
void __cmplog_rtn_hook_n(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
@ -93,36 +97,72 @@ void __cmplog_rtn_hook_n(const uint8_t *ptr1, const uint8_t *ptr2,
(void)ptr2;
(void)len;
}
void __cmplog_rtn_hook_n_extended(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
(void)ptr1;
(void)ptr2;
(void)len;
}
void __cmplog_rtn_hook_str(const uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr1;
(void)ptr2;
}
void __cmplog_rtn_hook_str_extended(const uint8_t *ptr1, uint8_t *ptr2) {
(void)ptr1;
(void)ptr2;
}
void __cmplog_rtn_hook_strn(uint8_t *ptr1, uint8_t *ptr2, uint64_t len) {
(void)ptr1;
(void)ptr2;
(void)len;
}
void __cmplog_rtn_hook_strn_extended(uint8_t *ptr1, uint8_t *ptr2,
uint64_t len) {
(void)ptr1;
(void)ptr2;
(void)len;
}
void __cmplog_rtn_gcc_stdstring_cstring(uint8_t *stdstring, uint8_t *cstring) {
(void)stdstring;
(void)cstring;
}
void __cmplog_rtn_gcc_stdstring_cstring_extended(uint8_t *stdstring,
uint8_t *cstring) {
(void)stdstring;
(void)cstring;
}
void __cmplog_rtn_gcc_stdstring_stdstring(uint8_t *stdstring1,
uint8_t *stdstring2) {
(void)stdstring1;
(void)stdstring2;
}
void __cmplog_rtn_gcc_stdstring_stdstring_extended(uint8_t *stdstring1,
uint8_t *stdstring2) {
(void)stdstring1;
(void)stdstring2;
}
void __cmplog_rtn_llvm_stdstring_cstring(uint8_t *stdstring, uint8_t *cstring) {
(void)stdstring;
(void)cstring;
}
void __cmplog_rtn_llvm_stdstring_cstring_extended(uint8_t *stdstring,
uint8_t *cstring) {
(void)stdstring;
(void)cstring;
}
void __cmplog_rtn_llvm_stdstring_stdstring(uint8_t *stdstring1,
uint8_t *stdstring2) {
(void)stdstring1;
(void)stdstring2;
}
void __cmplog_rtn_llvm_stdstring_stdstring_extended(uint8_t *stdstring1,
uint8_t *stdstring2) {
(void)stdstring1;
(void)stdstring2;
}

View File

@ -53,6 +53,7 @@ cmplog = ["common"] # Compile C code defining cmp log maps
forkserver = ["common"] # Compile C code for forkserver support
windows_asan = ["common"] # Compile C code for ASAN on Windows
whole_archive = [] # use +whole-archive to ensure the presence of weak symbols
cmplog_extended_instrumentation = [] # support for aflpp cmplog map, we will remove this once aflpp and libafl cmplog shares the same LLVM passes.
[build-dependencies]
bindgen = "0.68"

View File

@ -18,12 +18,6 @@ fn main() {
let cmp_map_size: usize = option_env!("LIBAFL_CMP_MAP_SIZE")
.map_or(Ok(65536), str::parse)
.expect("Could not parse LIBAFL_CMP_MAP_SIZE");
let aflpp_cmplog_map_w: usize = option_env!("LIBAFL_AFLPP_CMPLOG_MAP_W")
.map_or(Ok(65536), str::parse)
.expect("Could not parse LIBAFL_AFLPP_CMPLOG_MAP_W");
let aflpp_cmplog_map_h: usize = option_env!("LIBAFL_AFLPP_CMPLOG_MAP_W")
.map_or(Ok(32), str::parse)
.expect("Could not parse LIBAFL_AFLPP_CMPLOG_MAP_W");
let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W")
.map_or(Ok(65536), str::parse)
.expect("Could not parse LIBAFL_CMPLOG_MAP_W");
@ -42,10 +36,6 @@ fn main() {
pub const EDGES_MAP_SIZE: usize = {edges_map_size};
/// The size of the cmps map
pub const CMP_MAP_SIZE: usize = {cmp_map_size};
/// The width of the aflpp cmplog map
pub const AFLPP_CMPLOG_MAP_W: usize = {aflpp_cmplog_map_w};
/// The height of the aflpp cmplog map
pub const AFLPP_CMPLOG_MAP_H: usize = {aflpp_cmplog_map_h};
/// The width of the `CmpLog` map
pub const CMPLOG_MAP_W: usize = {cmplog_map_w};
/// The height of the `CmpLog` map
@ -58,8 +48,6 @@ fn main() {
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_CMP_MAP_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_AFLPP_CMPLOG_MAP_W");
println!("cargo:rerun-if-env-changed=LIBAFL_AFLPP_CMPLOG_MAP_H");
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_W");
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H");
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
@ -107,14 +95,6 @@ fn main() {
sancov_cmp
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("sancov_cmp.c"))
@ -166,18 +146,14 @@ fn main() {
#[cfg(unix)]
{
cc::Build::new()
.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
let mut cc = cc::Build::new();
#[cfg(feature = "cmplog_extended_instrumentation")]
cc.define("CMPLOG_EXTENDED", Some("1"));
cc.flag("-Wno-pointer-sign") // UNIX ONLY FLAGS
.flag("-Wno-sign-compare")
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("cmplog.c"))
@ -188,14 +164,6 @@ fn main() {
{
cc::Build::new()
.define("CMP_MAP_SIZE", Some(&*format!("{cmp_map_size}")))
.define(
"AFLPP_CMPLOG_MAP_W",
Some(&*format!("{aflpp_cmplog_map_w}")),
)
.define(
"AFLPP_CMPLOG_MAP_H",
Some(&*format!("{aflpp_cmplog_map_h}")),
)
.define("CMPLOG_MAP_W", Some(&*format!("{cmplog_map_w}")))
.define("CMPLOG_MAP_H", Some(&*format!("{cmplog_map_h}")))
.file(src_dir.join("cmplog.c"))

View File

@ -37,8 +37,10 @@ __attribute__((weak)) void *__asan_region_is_poisoned(const void *beg,
#endif
CmpLogMap *libafl_cmplog_map_ptr = &libafl_cmplog_map;
CmpLogMap *libafl_cmplog_map_ptr = &libafl_cmplog_map;
#ifdef CMPLOG_EXTENDED
CmpLogMapExtended *libafl_cmplog_map_extended_ptr = &libafl_cmplog_map_extended;
#endif
void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape,
uint64_t arg1, uint64_t arg2) {
@ -67,12 +69,14 @@ void __libafl_targets_cmplog_instructions(uintptr_t k, uint8_t shape,
void __libafl_targets_cmplog_instructions_extended(uintptr_t k, uint8_t shape,
uint64_t arg1, uint64_t arg2,
uint8_t attr) {
#ifdef CMPLOG_EXTENDED
if (!libafl_cmplog_enabled) { return; }
libafl_cmplog_enabled = false;
// printf("%ld %ld %ld\n", k, arg1, arg2);
uint16_t hits;
if (libafl_cmplog_map_extended_ptr->headers[k].type != CMPLOG_KIND_INS) {
libafl_cmplog_map_extended_ptr->headers[k].type = CMPLOG_KIND_INS;
if (libafl_cmplog_map_extended_ptr->headers[k].type != AFL_CMP_TYPE_INS) {
libafl_cmplog_map_extended_ptr->headers[k].type = AFL_CMP_TYPE_INS;
libafl_cmplog_map_extended_ptr->headers[k].hits = 1;
libafl_cmplog_map_extended_ptr->headers[k].shape = shape;
hits = 0;
@ -88,6 +92,14 @@ void __libafl_targets_cmplog_instructions_extended(uintptr_t k, uint8_t shape,
libafl_cmplog_map_extended_ptr->vals.operands[k][hits].v1 = arg2;
libafl_cmplog_map_extended_ptr->headers[k].attribute = attr;
libafl_cmplog_enabled = true;
#else
// just do nothing
(void)k;
(void)shape;
(void)arg1;
(void)arg2;
(void)attr;
#endif
}
// POSIX shenanigan to see if an area is mapped.
@ -161,6 +173,43 @@ void __libafl_targets_cmplog_routines_checked(uintptr_t k, const uint8_t *ptr1,
libafl_cmplog_enabled = true;
}
// cmplog routines after area check
void __libafl_targets_cmplog_routines_checked_extended(uintptr_t k,
const uint8_t *ptr1,
const uint8_t *ptr2,
size_t len) {
#ifdef CMPLOG_EXTENDED
libafl_cmplog_enabled = false;
uint32_t hits;
// printf("RTN: %ld %ld %ld %ld\n", k, *ptr1, *ptr2, len);
if (libafl_cmplog_map_extended_ptr->headers[k].type != AFL_CMP_TYPE_RTN) {
libafl_cmplog_map_extended_ptr->headers[k].type = AFL_CMP_TYPE_RTN;
libafl_cmplog_map_extended_ptr->headers[k].hits = 1;
libafl_cmplog_map_extended_ptr->headers[k].shape = len;
hits = 0;
} else {
hits = libafl_cmplog_map_extended_ptr->headers[k].hits++;
if (libafl_cmplog_map_extended_ptr->headers[k].shape < len) {
libafl_cmplog_map_extended_ptr->headers[k].shape =
len; // TODO; adjust len for AFL++'s cmplog protocol
}
}
hits &= CMPLOG_MAP_RTN_H - 1;
libafl_cmplog_map_extended_ptr->vals.routines[k][hits].v0_len = len;
libafl_cmplog_map_extended_ptr->vals.routines[k][hits].v1_len = len;
MEMCPY(libafl_cmplog_map_extended_ptr->vals.routines[k][hits].v0, ptr1, len);
MEMCPY(libafl_cmplog_map_extended_ptr->vals.routines[k][hits].v1, ptr2, len);
libafl_cmplog_enabled = true;
#else
// just do nothing
(void)k;
(void)ptr1;
(void)ptr2;
(void)len;
#endif
}
// Very generic cmplog routines callback
void __libafl_targets_cmplog_routines(uintptr_t k, const uint8_t *ptr1,
const uint8_t *ptr2) {
@ -290,19 +339,51 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t size) {
*/
void __cmplog_rtn_hook(const uint8_t *ptr1, const uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
int l1, l2;
if ((l1 = area_is_valid(ptr1, CMPLOG_RTN_LEN)) <= 0 ||
(l2 = area_is_valid(ptr2, CMPLOG_RTN_LEN)) <= 0) {
return;
}
int len = MIN(l1, l2);
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines(k, ptr1, ptr2);
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, len);
}
void __cmplog_rtn_hook_extended(const uint8_t *ptr1, const uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
int l1, l2;
if ((l1 = area_is_valid(ptr1, CMPLOG_RTN_LEN)) <= 0 ||
(l2 = area_is_valid(ptr2, CMPLOG_RTN_LEN)) <= 0) {
return;
}
int len = MIN(l1, l2);
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, ptr1, ptr2, len);
}
void __cmplog_rtn_hook_n(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
// this code is from AFL++
// but i don't know why afl++ just ignores the len argument
(void)(len);
__cmplog_rtn_hook(ptr1, ptr2);
}
void __cmplog_rtn_hook_n_extended(const uint8_t *ptr1, const uint8_t *ptr2,
uint64_t len) {
(void)(len);
__cmplog_rtn_hook_extended(ptr1, ptr2);
}
/* hook for string functions, eg. strcmp, strcasecmp etc. */
void __cmplog_rtn_hook_str(const uint8_t *ptr1, uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
@ -325,6 +406,28 @@ void __cmplog_rtn_hook_str(const uint8_t *ptr1, uint8_t *ptr2) {
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, l);
}
/* hook for string functions, eg. strcmp, strcasecmp etc. */
void __cmplog_rtn_hook_str_extended(const uint8_t *ptr1, uint8_t *ptr2) {
if (!libafl_cmplog_enabled) { return; }
if (unlikely(!ptr1 || !ptr2)) return;
// these strnlen could indeed fail. but if it fails here it will sigsegv in
// the following hooked function call anyways
int len1 = strnlen(ptr1, 30) + 1;
int len2 = strnlen(ptr2, 30) + 1;
int l = MAX(len1, len2);
l = MIN(l, area_is_valid(ptr1, l + 1)); // can we really access it? check
l = MIN(l, area_is_valid(ptr2, l + 1)); // can we really access it? check
if (l < 2) return;
intptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, ptr1, ptr2, l);
}
/* hook for string with length functions, eg. strncmp, strncasecmp etc.
Note that we ignore the len parameter and take longer strings if present. */
@ -350,10 +453,35 @@ void __cmplog_rtn_hook_strn(uint8_t *ptr1, uint8_t *ptr2, uint64_t len) {
__libafl_targets_cmplog_routines_checked(k, ptr1, ptr2, l);
}
/* hook for string with length functions, eg. strncmp, strncasecmp etc.
Note that we ignore the len parameter and take longer strings if present. */
void __cmplog_rtn_hook_strn_extended(uint8_t *ptr1, uint8_t *ptr2,
uint64_t len) {
if (!libafl_cmplog_enabled) { return; }
if (unlikely(!ptr1 || !ptr2)) return;
int len0 = MIN(len, 31); // cap by 31
// these strnlen could indeed fail. but if it fails here it will sigsegv in
// the following hooked function call anyways
int len1 = strnlen(ptr1, len0);
int len2 = strnlen(ptr2, len0);
int l = MAX(len1, len2);
l = MIN(l, area_is_valid(ptr1, l + 1)); // can we really access it? check
l = MIN(l, area_is_valid(ptr2, l + 1)); // can we really access it? check
if (l < 2) return;
intptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, ptr1, ptr2, l);
}
// gcc libstdc++
// _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE7compareEPKc
static const uint8_t *get_gcc_stdstring(const uint8_t *string) {
static inline const uint8_t *get_gcc_stdstring(const uint8_t *string) {
uint32_t *len = (uint32_t *)(string + 8);
if (*len < 16) { // in structure
@ -366,7 +494,7 @@ static const uint8_t *get_gcc_stdstring(const uint8_t *string) {
// llvm libc++ _ZNKSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocator
// IcEEE7compareEmmPKcm
static const uint8_t *get_llvm_stdstring(const uint8_t *string) {
static inline const uint8_t *get_llvm_stdstring(const uint8_t *string) {
// length is in: if ((string[0] & 1) == 0) {uint8_t len = (string[0] >> 1);}
// or: if (string[0] & 1) {uint32_t *len = (uint32_t *) (string + 8);}
@ -399,6 +527,28 @@ void __cmplog_rtn_gcc_stdstring_cstring(const uint8_t *stdstring,
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, string_ptr, cstring, len);
}
void __cmplog_rtn_gcc_stdstring_cstring_extended(const uint8_t *stdstring,
const uint8_t *cstring) {
if (!libafl_cmplog_enabled) { return; }
// This gcc string structure has 32 bytes of content at max
// That's what 32 means!
if (area_is_valid(stdstring, 32) <= 0) { return; }
int l1 = area_is_valid(cstring, CMPLOG_RTN_LEN);
if (l1 <= 0) { return; }
const uint8_t *string_ptr = get_gcc_stdstring(stdstring);
int l2 = area_is_valid(string_ptr, CMPLOG_RTN_LEN);
if (l2 <= 0) { return; }
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, string_ptr, cstring,
len);
}
void __cmplog_rtn_gcc_stdstring_stdstring(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
@ -422,6 +572,29 @@ void __cmplog_rtn_gcc_stdstring_stdstring(const uint8_t *stdstring1,
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, string_ptr1, string_ptr2, len);
}
void __cmplog_rtn_gcc_stdstring_stdstring_extended(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring1, 32) <= 0) { return; };
if (area_is_valid(stdstring2, 32) <= 0) { return; };
const uint8_t *string_ptr1 = get_gcc_stdstring(stdstring1);
int l1 = area_is_valid(string_ptr1, CMPLOG_RTN_LEN);
if (l1 <= 0) { return; }
const uint8_t *string_ptr2 = get_gcc_stdstring(stdstring2);
int l2 = area_is_valid(string_ptr2, CMPLOG_RTN_LEN);
if (l2 <= 0) { return; }
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, string_ptr1, string_ptr2,
len);
}
void __cmplog_rtn_llvm_stdstring_cstring(const uint8_t *stdstring,
const uint8_t *cstring) {
@ -443,6 +616,27 @@ void __cmplog_rtn_llvm_stdstring_cstring(const uint8_t *stdstring,
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, string_ptr, cstring, len);
}
void __cmplog_rtn_llvm_stdstring_cstring_extended(const uint8_t *stdstring,
const uint8_t *cstring) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring, 32) <= 0) { return; }
int l1 = area_is_valid(cstring, CMPLOG_RTN_LEN);
if (l1 <= 0) { return; }
const uint8_t *string_ptr = get_llvm_stdstring(stdstring);
int l2 = area_is_valid(string_ptr, CMPLOG_RTN_LEN);
if (l2 <= 0) { return; }
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, string_ptr, cstring,
len);
}
void __cmplog_rtn_llvm_stdstring_stdstring(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
@ -466,3 +660,26 @@ void __cmplog_rtn_llvm_stdstring_stdstring(const uint8_t *stdstring1,
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked(k, string_ptr1, string_ptr2, len);
}
void __cmplog_rtn_llvm_stdstring_stdstring_extended(const uint8_t *stdstring1,
const uint8_t *stdstring2) {
if (!libafl_cmplog_enabled) { return; }
if (area_is_valid(stdstring1, 32) <= 0) { return; };
if (area_is_valid(stdstring2, 32) <= 0) { return; };
const uint8_t *string_ptr1 = get_gcc_stdstring(stdstring1);
int l1 = area_is_valid(get_gcc_stdstring(stdstring1), CMPLOG_RTN_LEN);
if (l1 <= 0) { return; }
const uint8_t *string_ptr2 = get_gcc_stdstring(stdstring2);
int l2 = area_is_valid(get_gcc_stdstring(stdstring2), CMPLOG_RTN_LEN);
if (l2 <= 0) { return; }
int len = MIN(31, MIN(l1, l2));
uintptr_t k = RETADDR;
k = (k >> 4) ^ (k << 8);
k &= CMPLOG_MAP_W - 1;
__libafl_targets_cmplog_routines_checked_extended(k, string_ptr1, string_ptr2,
len);
}

View File

@ -11,14 +11,26 @@
#define CMPLOG_MAP_H 32
#endif
#define CMPLOG_RTN_LEN 32
// difference between aflpp and libafl
#ifdef CMPLOG_EXTENDED
#define CMPLOG_RTN_LEN 31
#else
#define CMPLOG_RTN_LEN 32
#endif
#define CMPLOG_MAP_RTN_H \
((CMPLOG_MAP_H * sizeof(CmpLogInstruction)) / sizeof(CmpLogRoutine))
#define CMPLOG_MAP_RTN_EXTENDED_H \
((CMPLOG_MAP_H * sizeof(CmpLogInstructionExtended)) / sizeof(CmpLogRoutine))
#define CMPLOG_KIND_INS 0
#define CMPLOG_KIND_RTN 1
// Same, difference between aflpp and libafl
#define AFL_CMP_TYPE_INS 1
#define AFL_CMP_TYPE_RTN 2
typedef struct CmpLogHeader {
uint16_t hits;
uint8_t shape;
@ -53,11 +65,25 @@ typedef struct CmpLogInstruction {
uint64_t v1;
} CmpLogInstruction;
typedef struct CmpLogInstructionExtended {
uint64_t v0;
uint64_t v1;
uint64_t v0_128;
uint64_t v1_128;
} CmpLogInstructionExtended;
typedef struct CmpLogRoutine {
uint8_t v0[CMPLOG_RTN_LEN];
uint8_t v1[CMPLOG_RTN_LEN];
} CmpLogRoutine;
typedef struct CmpLogRoutineExtended {
uint8_t v0[CMPLOG_RTN_LEN];
uint8_t v0_len;
uint8_t v1[CMPLOG_RTN_LEN];
uint8_t v1_len;
} CmpLogRoutineExtended;
typedef struct CmpLogMap {
CmpLogHeader headers[CMPLOG_MAP_W];
union {
@ -69,8 +95,8 @@ typedef struct CmpLogMap {
typedef struct CmpLogMapExtended {
CmpLogHeaderExtended headers[CMPLOG_MAP_W];
union {
CmpLogInstruction operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
CmpLogRoutine routines[CMPLOG_MAP_W][CMPLOG_MAP_RTN_H];
CmpLogInstructionExtended operands[CMPLOG_MAP_W][CMPLOG_MAP_H];
CmpLogRoutineExtended routines[CMPLOG_MAP_W][CMPLOG_MAP_RTN_EXTENDED_H];
} vals;
} CmpLogMapExtended;

View File

@ -17,7 +17,7 @@ use libafl::{
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use stages::*;
use crate::{AFLPP_CMPLOG_MAP_H, AFLPP_CMPLOG_MAP_W, CMPLOG_MAP_H, CMPLOG_MAP_W};
use crate::{CMPLOG_MAP_H, CMPLOG_MAP_W};
// CONSTANTS
@ -31,14 +31,16 @@ pub const CMPLOG_RTN_LEN: usize = 32;
pub const CMPLOG_MAP_RTN_H: usize = (CMPLOG_MAP_H * core::mem::size_of::<CmpLogInstruction>())
/ core::mem::size_of::<CmpLogRoutine>();
/// The height of extended rountine map
pub const CMPLOG_MAP_RTN_EXTENDED_H: usize = CMPLOG_MAP_H
* core::mem::size_of::<AFLppCmpLogOperands>()
/ core::mem::size_of::<AFLppCmpLogFnOperands>();
/// `CmpLog` instruction kind
pub const CMPLOG_KIND_INS: u8 = 0;
/// `CmpLog` routine kind
pub const CMPLOG_KIND_RTN: u8 = 1;
/// The height for RTN
pub const AFL_CMPLOG_MAP_RTN_H: usize = AFLPP_CMPLOG_MAP_H / 2;
/// The AFL++ `CMP_TYPE_INS`
pub const AFL_CMP_TYPE_INS: u32 = 1;
/// The AFL++ `CMP_TYPE_RTN`
@ -269,8 +271,8 @@ impl Debug for CmpLogVals {
#[repr(C, packed)]
/// Comparison values
pub union AFLppCmpLogVals {
operands: [[AFLppCmpLogOperands; AFLPP_CMPLOG_MAP_H]; AFLPP_CMPLOG_MAP_W],
fn_operands: [[AFLppCmpLogFnOperands; AFL_CMPLOG_MAP_RTN_H]; AFLPP_CMPLOG_MAP_W],
operands: [[AFLppCmpLogOperands; CMPLOG_MAP_H]; CMPLOG_MAP_W],
fn_operands: [[AFLppCmpLogFnOperands; CMPLOG_MAP_RTN_EXTENDED_H]; CMPLOG_MAP_W],
}
impl Debug for AFLppCmpLogVals {
@ -282,15 +284,13 @@ impl Debug for AFLppCmpLogVals {
impl AFLppCmpLogVals {
#[must_use]
/// Reference comparison values as comparison operands
pub fn operands(&self) -> &[[AFLppCmpLogOperands; AFLPP_CMPLOG_MAP_H]; AFLPP_CMPLOG_MAP_W] {
pub fn operands(&self) -> &[[AFLppCmpLogOperands; CMPLOG_MAP_H]; CMPLOG_MAP_W] {
unsafe { &self.operands }
}
#[must_use]
/// Mutably reference comparison values as comparison operands
pub fn operands_mut(
&mut self,
) -> &mut [[AFLppCmpLogOperands; AFLPP_CMPLOG_MAP_H]; AFLPP_CMPLOG_MAP_W] {
pub fn operands_mut(&mut self) -> &mut [[AFLppCmpLogOperands; CMPLOG_MAP_H]; CMPLOG_MAP_W] {
unsafe { &mut self.operands }
}
@ -298,7 +298,7 @@ impl AFLppCmpLogVals {
/// Reference comparison values as comparison function operands
pub fn fn_operands(
&self,
) -> &[[AFLppCmpLogFnOperands; AFL_CMPLOG_MAP_RTN_H]; AFLPP_CMPLOG_MAP_W] {
) -> &[[AFLppCmpLogFnOperands; CMPLOG_MAP_RTN_EXTENDED_H]; CMPLOG_MAP_W] {
unsafe { &self.fn_operands }
}
@ -306,7 +306,7 @@ impl AFLppCmpLogVals {
/// Mutably reference comparison values as comparison function operands
pub fn fn_operands_mut(
&mut self,
) -> &mut [[AFLppCmpLogFnOperands; AFL_CMPLOG_MAP_RTN_H]; AFLPP_CMPLOG_MAP_W] {
) -> &mut [[AFLppCmpLogFnOperands; CMPLOG_MAP_RTN_EXTENDED_H]; CMPLOG_MAP_W] {
unsafe { &mut self.fn_operands }
}
}
@ -412,6 +412,7 @@ pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
/// The globale `CmpLog` map, aflpp style
#[no_mangle]
#[cfg(feature = "cmplog_extended_instrumentation")]
#[allow(clippy::large_stack_arrays)]
pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap {
headers: [AFLppCmpLogHeader { data: [0; 8] }; CMPLOG_MAP_W],
@ -426,13 +427,14 @@ pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap {
};
pub use libafl_cmplog_map as CMPLOG_MAP;
#[cfg(feature = "cmplog_extended_instrumentation")]
pub use libafl_cmplog_map_extended as CMPLOG_MAP_EXTENDED;
#[derive(Debug, Clone)]
#[repr(C, packed)]
/// Comparison map compatible with AFL++ cmplog instrumentation
pub struct AFLppCmpLogMap {
headers: [AFLppCmpLogHeader; AFLPP_CMPLOG_MAP_W],
headers: [AFLppCmpLogHeader; CMPLOG_MAP_W],
vals: AFLppCmpLogVals,
}
@ -500,7 +502,7 @@ impl<'de> Deserialize<'de> for AFLppCmpLogMap {
impl CmpMap for AFLppCmpLogMap {
fn len(&self) -> usize {
AFLPP_CMPLOG_MAP_W
CMPLOG_MAP_W
}
fn executions_for(&self, idx: usize) -> usize {
@ -509,15 +511,15 @@ impl CmpMap for AFLppCmpLogMap {
fn usable_executions_for(&self, idx: usize) -> usize {
if self.headers[idx]._type() == AFL_CMP_TYPE_INS {
if self.executions_for(idx) < AFLPP_CMPLOG_MAP_H {
if self.executions_for(idx) < CMPLOG_MAP_H {
self.executions_for(idx)
} else {
AFLPP_CMPLOG_MAP_H
CMPLOG_MAP_H
}
} else if self.executions_for(idx) < AFL_CMPLOG_MAP_RTN_H {
} else if self.executions_for(idx) < CMPLOG_MAP_RTN_H {
self.executions_for(idx)
} else {
AFL_CMPLOG_MAP_RTN_H
CMPLOG_MAP_RTN_H
}
}

View File

@ -18,6 +18,8 @@ use libafl_bolts::{ownedref::OwnedRefMut, Named};
use serde::{Deserialize, Serialize};
use crate::cmps::AFLppCmpLogMap;
#[cfg(feature = "cmplog_extended_instrumentation")]
use crate::cmps::CMPLOG_ENABLED;
/* From AFL++ cmplog.h
@ -147,6 +149,16 @@ where
S: UsesInput + Debug + HasMetadata,
{
fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> {
#[cfg(feature = "cmplog_extended_instrumentation")]
unsafe {
// if the target is compiled with aflpp and you are running forkserver then this is not needed
// because with forkserver, you have two executors (processes), one is dedicated for edge-cov
// the other dedicated for cmplog.
// however if it is in-process, then cmplog instrumentation is in the same binary as the edge-cov binary
// (so we only have one executable)
// therefore we need to turn this thing on and off to change this according to what executors we are using
CMPLOG_ENABLED = 1;
}
self.cmp_map.as_mut().reset()?;
Ok(())
}
@ -157,6 +169,10 @@ where
_input: &S::Input,
_exit_kind: &ExitKind,
) -> Result<(), Error> {
#[cfg(feature = "cmplog_extended_instrumentation")]
unsafe {
CMPLOG_ENABLED = 0;
}
if self.add_meta {
self.add_cmpvalues_meta(state);
}
@ -295,6 +311,18 @@ impl<'a> CmpObserverMetadata<'a, AFLppCmpLogMap> for AFLppCmpValuesMetadata {
} else {
// push into new_cmpvals
// println!("Adding to new_cmpvals");
/*
unsafe {
println!(
"idx {:#?} type {:#?} sz {:#?} ptr1 {:p} val1 {:x}",
i,
cmp_map.headers()[i]._type(),
cmp_map.headers()[i].shape(),
&cmp_map.vals.operands[i][0],
cmp_map.vals.operands[i][0].v0(),
);
}
*/
for j in 0..execs {
if let Some(val) = cmp_map.values_of(i, j) {
cmp_values.push(val);