add feedback for improving msd

This commit is contained in:
Alwin Berger 2022-01-17 20:51:52 +01:00
parent d2d2862727
commit d4d86927b7
3 changed files with 124 additions and 29 deletions

View File

@ -1,5 +1,9 @@
//! A singlethreaded QEMU fuzzer that can auto-restart. //! A singlethreaded QEMU fuzzer that can auto-restart.
use libafl::feedbacks::Feedback;
use crate::worst::HitImprovingFeedback;
use crate::worst::HitFeedback;
use hashbrown::HashMap;
use libafl::stats::SimpleStats; use libafl::stats::SimpleStats;
use libafl::events::SimpleEventManager; use libafl::events::SimpleEventManager;
use clap::{App, Arg}; use clap::{App, Arg};
@ -113,6 +117,11 @@ pub fn main() {
.help("Timeout for each individual execution, in milliseconds") .help("Timeout for each individual execution, in milliseconds")
.default_value("1000"), .default_value("1000"),
) )
.arg(
Arg::new("edges")
.long("libafl-edges")
.takes_value(true),
)
.try_get_matches_from(filter_qemu_args()) .try_get_matches_from(filter_qemu_args())
{ {
Ok(res) => res, Ok(res) => res,
@ -165,8 +174,12 @@ pub fn main() {
); );
let kernel = PathBuf::from(res.value_of("k").unwrap().to_string()); let kernel = PathBuf::from(res.value_of("k").unwrap().to_string());
let edges = match res.value_of("edges") {
Some(st) => Some(PathBuf::from(st.to_string())),
None => None
};
fuzz(out_dir, crashes, in_dir, tokens, logfile, timeout, kernel) fuzz(out_dir, crashes, in_dir, tokens, logfile, timeout, kernel, edges)
.expect("An error occurred while fuzzing"); .expect("An error occurred while fuzzing");
} }
@ -192,6 +205,7 @@ fn fuzz(
logfile: PathBuf, logfile: PathBuf,
timeout: Duration, timeout: Duration,
kernel: PathBuf, kernel: PathBuf,
dump_edges: Option<PathBuf>,
) -> Result<(), Error> { ) -> Result<(), Error> {
env::remove_var("LD_LIBRARY_PATH"); env::remove_var("LD_LIBRARY_PATH");
@ -286,16 +300,28 @@ fn fuzz(
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let target_map : HashMap<(u64,u64),u8> = match dump_edges {
None => HashMap::new(),
Some(ref s) => {
let raw = fs::read(s).expect("Can not read dumped edges");
let hmap : HashMap<(u64,u64),u8> = ron::from_str(&String::from_utf8_lossy(&raw)).expect("Can not parse HashMap");
hmap
},
};
let feedback = feedback_or!( let feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
MapHitIncreaseFeedback::new(), HitImprovingFeedback::new(target_map.clone())
// Time feedback, this one does not need a feedback state
TimeFeedback::new_with_observer(&time_observer)
); );
// let feedback = feedback_or!(
// // New maximization map feedback linked to the edges observer and the feedback state
// MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
// MapHitIncreaseFeedback::new(),
// // Time feedback, this one does not need a feedback state
// TimeFeedback::new_with_observer(&time_observer)
// );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let objective = CrashFeedback::new(); let objective = HitFeedback::new(target_map,0.0);
// create a State from scratch // create a State from scratch
let mut state = { let mut state = {

View File

@ -1,5 +1,6 @@
//! A singlethreaded QEMU fuzzer that can auto-restart. //! A singlethreaded QEMU fuzzer that can auto-restart.
use libafl::feedbacks::CrashFeedback;
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use libafl::corpus::Corpus; use libafl::corpus::Corpus;
@ -234,7 +235,7 @@ fn fuzz(
let feedback = DumpMapFeedback::with_dump(dump_edges); let feedback = DumpMapFeedback::with_dump(dump_edges);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let objective = HitFeedback::new(); let objective = CrashFeedback::new();
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(

View File

@ -10,6 +10,7 @@ use libafl::state::HasMetadata;
use libafl_qemu::edges::QemuEdgesMapMetadata; use libafl_qemu::edges::QemuEdgesMapMetadata;
use libafl::observers::MapObserver; use libafl::observers::MapObserver;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cmp;
use libafl::{ use libafl::{
bolts::{ bolts::{
@ -145,7 +146,10 @@ where
/// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched. /// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct HitFeedback {} pub struct HitFeedback {
target_map: HashMap<(u64,u64),u8>,
target_msd: f64,
}
impl<I, S> Feedback<I, S> for HitFeedback impl<I, S> Feedback<I, S> for HitFeedback
where where
@ -168,26 +172,17 @@ where
// let observer = _observers.match_name::<HitcountsMapObserver<O>>("edges").expect("SelectedEdgeObserver not found"); // let observer = _observers.match_name::<HitcountsMapObserver<O>>("edges").expect("SelectedEdgeObserver not found");
let observer = _observers.match_name::<HitcountsMapObserver<VariableMapObserver<u8>>>("edges") let observer = _observers.match_name::<HitcountsMapObserver<VariableMapObserver<u8>>>("edges")
.expect("HitcountsMapObserver not found"); .expect("HitcountsMapObserver not found");
let mut hit_target: bool = true; if self.target_map.len() == 0 { return Ok(true) };
//check if we've hit any targets.
// let inc : u64 = (0x401180); let mut sum_of_square_difference : u64 = 0; // does not include found edges not in target
// let call1 : u64 = (0x40119f); for (edg, val) in &self.target_map {
// let call2 : u64 = (0x4011b0); match observer.edgemap.get(&edg) {
// let call3 : u64 = (0x4011c8); Some(x) => sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)) as u64).pow(2),
let to_check : Vec<(u64,u64)> = vec![ None => sum_of_square_difference+=(*val as u64).pow(2),
(0x401190,0x4011c8), // start -> call
(0x40119b,0x4011b0), // cmp -> call
(0x4011b5,0x40119f), // cmp -> call
];
let expected : Vec<u8> = vec![ 1, 1, 1];
let combo = to_check.iter().zip(expected.iter());
for (edg, val) in combo {
// println!("Feedback Len: {} Cap: {}",observer.edgemap.len(),observer.edgemap.capacity());
match observer.edgemap.get(edg) {
Some(x) => hit_target &= val == x,
None =>hit_target = false
} }
} }
let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64);
let hit_target = mean_sum_of_squares <= 1.0;
if hit_target { if hit_target {
Ok(true) Ok(true)
} else { } else {
@ -206,14 +201,14 @@ impl Named for HitFeedback {
impl HitFeedback { impl HitFeedback {
/// Creates a new [`HitFeedback`] /// Creates a new [`HitFeedback`]
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new(target_map: HashMap<(u64,u64),u8>, target_msd: f64) -> Self {
Self {} Self {target_map: target_map, target_msd: target_msd}
} }
} }
impl Default for HitFeedback { impl Default for HitFeedback {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new(HashMap::new(),0.0)
} }
} }
@ -274,3 +269,76 @@ impl Default for MapHitIncreaseFeedback {
Self::new() Self::new()
} }
} }
//===================================================================
/// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct HitImprovingFeedback {
target_map: HashMap<(u64,u64),u8>,
best_msd: f64,
}
impl<I, S> Feedback<I, S> for HitImprovingFeedback
where
I: Input,
S: HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I>,
OT: ObserversTuple<I, S>,
{
// TODO Replace with match_name_type when stable
// let observer = _observers.match_name::<HitcountsMapObserver<O>>("edges").expect("SelectedEdgeObserver not found");
let observer = _observers.match_name::<HitcountsMapObserver<VariableMapObserver<u8>>>("edges")
.expect("HitcountsMapObserver not found");
if self.target_map.len() == 0 { return Ok(true) };
let mut sum_of_square_difference : u64 = 0; // does not include found edges not in target
for (edg, val) in &self.target_map {
match observer.edgemap.get(&edg) {
Some(x) => sum_of_square_difference+=((cmp::max(*x,*val)-cmp::min(*x,*val)) as u64).pow(2),
None => sum_of_square_difference+=(*val as u64).pow(2),
}
}
let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64);
let hit_target = mean_sum_of_squares <= self.best_msd;
eprintln!("in worst, {}",hit_target);
if hit_target {
self.best_msd = mean_sum_of_squares;
Ok(true)
} else {
Ok(false)
}
}
}
impl Named for HitImprovingFeedback {
#[inline]
fn name(&self) -> &str {
"HitFeedback"
}
}
impl HitImprovingFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new(target_map: HashMap<(u64,u64),u8>) -> Self {
Self {target_map: target_map, best_msd: f64::MAX}
}
}
impl Default for HitImprovingFeedback {
fn default() -> Self {
Self::new(HashMap::new())
}
}