diff --git a/fuzzers/wcet_qemu_sys/src/fuzzer.rs b/fuzzers/wcet_qemu_sys/src/fuzzer.rs index b5d0d59698..a6b95f8fde 100644 --- a/fuzzers/wcet_qemu_sys/src/fuzzer.rs +++ b/fuzzers/wcet_qemu_sys/src/fuzzer.rs @@ -1,5 +1,9 @@ //! 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::events::SimpleEventManager; use clap::{App, Arg}; @@ -113,6 +117,11 @@ pub fn main() { .help("Timeout for each individual execution, in milliseconds") .default_value("1000"), ) + .arg( + Arg::new("edges") + .long("libafl-edges") + .takes_value(true), + ) .try_get_matches_from(filter_qemu_args()) { Ok(res) => res, @@ -165,8 +174,12 @@ pub fn main() { ); 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"); } @@ -192,6 +205,7 @@ fn fuzz( logfile: PathBuf, timeout: Duration, kernel: PathBuf, + dump_edges: Option, ) -> Result<(), Error> { env::remove_var("LD_LIBRARY_PATH"); @@ -286,16 +300,28 @@ fn fuzz( // Feedback to rate the interestingness of an input // 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!( - // 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) + HitImprovingFeedback::new(target_map.clone()) ); + // 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 - let objective = CrashFeedback::new(); + let objective = HitFeedback::new(target_map,0.0); // create a State from scratch let mut state = { diff --git a/fuzzers/wcet_qemu_sys/src/showmap.rs b/fuzzers/wcet_qemu_sys/src/showmap.rs index 7c764f9348..d112bb765a 100644 --- a/fuzzers/wcet_qemu_sys/src/showmap.rs +++ b/fuzzers/wcet_qemu_sys/src/showmap.rs @@ -1,5 +1,6 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. +use libafl::feedbacks::CrashFeedback; use std::fs::File; use std::path::Path; use libafl::corpus::Corpus; @@ -234,7 +235,7 @@ fn fuzz( let feedback = DumpMapFeedback::with_dump(dump_edges); // 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 let mut state = StdState::new( diff --git a/fuzzers/wcet_qemu_sys/src/worst.rs b/fuzzers/wcet_qemu_sys/src/worst.rs index 32e21026c4..1982b7bbab 100644 --- a/fuzzers/wcet_qemu_sys/src/worst.rs +++ b/fuzzers/wcet_qemu_sys/src/worst.rs @@ -10,6 +10,7 @@ use libafl::state::HasMetadata; use libafl_qemu::edges::QemuEdgesMapMetadata; use libafl::observers::MapObserver; use serde::{Deserialize, Serialize}; +use std::cmp; use libafl::{ bolts::{ @@ -145,7 +146,10 @@ where /// A [`HitFeedback`] reports as interesting when all predicted worst case edges have been matched. #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct HitFeedback {} +pub struct HitFeedback { + target_map: HashMap<(u64,u64),u8>, + target_msd: f64, +} impl Feedback for HitFeedback where @@ -168,26 +172,17 @@ where // let observer = _observers.match_name::>("edges").expect("SelectedEdgeObserver not found"); let observer = _observers.match_name::>>("edges") .expect("HitcountsMapObserver not found"); - let mut hit_target: bool = true; - //check if we've hit any targets. - // let inc : u64 = (0x401180); - // let call1 : u64 = (0x40119f); - // let call2 : u64 = (0x4011b0); - // let call3 : u64 = (0x4011c8); - let to_check : Vec<(u64,u64)> = vec![ - (0x401190,0x4011c8), // start -> call - (0x40119b,0x4011b0), // cmp -> call - (0x4011b5,0x40119f), // cmp -> call - ]; - let expected : Vec = 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 + 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 <= 1.0; if hit_target { Ok(true) } else { @@ -206,14 +201,14 @@ impl Named for HitFeedback { impl HitFeedback { /// Creates a new [`HitFeedback`] #[must_use] - pub fn new() -> Self { - Self {} + pub fn new(target_map: HashMap<(u64,u64),u8>, target_msd: f64) -> Self { + Self {target_map: target_map, target_msd: target_msd} } } impl Default for HitFeedback { fn default() -> Self { - Self::new() + Self::new(HashMap::new(),0.0) } } @@ -273,4 +268,77 @@ impl Default for MapHitIncreaseFeedback { fn default() -> Self { 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 Feedback for HitImprovingFeedback +where + I: Input, + S: HasClientPerfMonitor, +{ + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &I, + _observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + // TODO Replace with match_name_type when stable + // let observer = _observers.match_name::>("edges").expect("SelectedEdgeObserver not found"); + let observer = _observers.match_name::>>("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()) + } } \ No newline at end of file