Add function call level granularity for coverage accounting (#552)

* Add func call level granularity for coverage accounting

* code linting
This commit is contained in:
Chaofan Shou 2022-02-24 01:16:12 -08:00 committed by GitHub
parent 04c8e96923
commit df84d39242
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 6 deletions

View File

@ -1,6 +1,8 @@
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses}; use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
use std::env; use std::env;
const GRANULARITY: &str = "FUNC";
pub fn main() { pub fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if args.len() > 1 { if args.len() > 1 {
@ -25,6 +27,7 @@ pub fn main() {
.link_staticlib(&dir, "libfuzzer_libpng") .link_staticlib(&dir, "libfuzzer_libpng")
.add_arg("-fsanitize-coverage=trace-pc-guard") .add_arg("-fsanitize-coverage=trace-pc-guard")
.add_pass(LLVMPasses::CoverageAccounting) .add_pass(LLVMPasses::CoverageAccounting)
.add_passes_arg(format!("-granularity={}", GRANULARITY))
.run() .run()
.expect("Failed to run the wrapped compiler") .expect("Failed to run the wrapped compiler")
{ {

View File

@ -23,8 +23,7 @@ pub fn main() {
.parse_args(&args) .parse_args(&args)
.expect("Failed to parse the command line") .expect("Failed to parse the command line")
.add_pass(LLVMPasses::AFLCoverage) .add_pass(LLVMPasses::AFLCoverage)
.add_arg("-mllvm") .add_passes_arg("-ctx") // Context sensitive coverage
.add_arg("-ctx") // Context sensitive coverage
.link_staticlib(&dir, "libfuzzer_libpng") .link_staticlib(&dir, "libfuzzer_libpng")
.run() .run()
.expect("Failed to run the wrapped compiler") .expect("Failed to run the wrapped compiler")

View File

@ -77,6 +77,7 @@ pub struct ClangWrapper {
cc_args: Vec<String>, cc_args: Vec<String>,
link_args: Vec<String>, link_args: Vec<String>,
passes: Vec<LLVMPasses>, passes: Vec<LLVMPasses>,
passes_args: Vec<String>,
} }
#[allow(clippy::match_same_arms)] // for the linking = false wip for "shared" #[allow(clippy::match_same_arms)] // for the linking = false wip for "shared"
@ -264,6 +265,10 @@ impl CompilerWrapper for ClangWrapper {
args.push("-Xclang".into()); args.push("-Xclang".into());
args.push(pass.path().into_os_string().into_string().unwrap()); args.push(pass.path().into_os_string().into_string().unwrap());
} }
for passes_arg in &self.passes_args {
args.push("-mllvm".into());
args.push(passes_arg.into());
}
if self.linking { if self.linking {
if self.x_set { if self.x_set {
args.push("-x".into()); args.push("-x".into());
@ -325,6 +330,7 @@ impl ClangWrapper {
cc_args: vec![], cc_args: vec![],
link_args: vec![], link_args: vec![],
passes: vec![], passes: vec![],
passes_args: vec![],
is_silent: false, is_silent: false,
} }
} }
@ -359,6 +365,15 @@ impl ClangWrapper {
self self
} }
/// Add LLVM pass arguments
pub fn add_passes_arg<S>(&mut self, arg: S) -> &'_ mut Self
where
S: AsRef<str>,
{
self.passes_args.push(arg.as_ref().to_string());
self
}
/// Set if linking /// Set if linking
pub fn linking(&mut self, value: bool) -> &'_ mut Self { pub fn linking(&mut self, value: bool) -> &'_ mut Self {
self.linking = value; self.linking = value;

View File

@ -54,14 +54,61 @@ typedef uint32_t prev_loc_t;
#define MAP_SIZE LIBAFL_ACCOUNTING_MAP_SIZE #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"), \
};
using namespace llvm; using namespace llvm;
enum AccountingGranularity {
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<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<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> ThreadSafe("thread_safe", cl::desc("Use the thread safe instrumentation"), cl::init(false), cl::NotHidden);
namespace { 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;
}
}
return 0;
}
#ifdef USE_NEW_PM #ifdef USE_NEW_PM
class AFLCoverage : public PassInfoMixin<AFLCoverage> { class AFLCoverage : public PassInfoMixin<AFLCoverage> {
public: public:
@ -72,7 +119,10 @@ class AFLCoverage : public ModulePass {
static char ID; static char ID;
AFLCoverage() : ModulePass(ID) { AFLCoverage() : ModulePass(ID) {
#endif #endif
granularity = StringSwitch<AccountingGranularity>(GranularityStr)
.Case("BB", BB_GRAN)
.Case("FUNC", FUNC_GRAN)
.Default(UKNOWN_GRAN);
// initInstrumentList(); // initInstrumentList();
} }
@ -86,6 +136,7 @@ class AFLCoverage : public ModulePass {
protected: protected:
uint32_t map_size = MAP_SIZE; uint32_t map_size = MAP_SIZE;
uint32_t function_minimum_size = 1; uint32_t function_minimum_size = 1;
AccountingGranularity granularity;
}; };
@ -196,12 +247,20 @@ bool AFLCoverage::runOnModule(Module &M) {
// Start with 1 to implicitly track edge coverage too // Start with 1 to implicitly track edge coverage too
uint32_t MemCnt = 1; uint32_t MemCnt = 1;
for (auto &I : BB) { for (auto &I : BB) {
switch (granularity) {
case BB_GRAN:
if (I.mayReadFromMemory() || I.mayWriteToMemory()) if (I.mayReadFromMemory() || I.mayWriteToMemory())
++MemCnt; ++MemCnt;
break;
case FUNC_GRAN:
if (auto *C = dyn_cast<CallInst>(&I)) {
auto F = C->getCalledFunction();
MemCnt += isSecuritySensitiveFunction(F);
}
break;
}
} }
/* Make up cur_loc */ /* Make up cur_loc */
cur_loc = RandBelow(map_size); cur_loc = RandBelow(map_size);