diff --git a/fuzzers/FRET/src/systemstate/mutational.rs b/fuzzers/FRET/src/systemstate/mutational.rs index 707830c995..3c22968de3 100644 --- a/fuzzers/FRET/src/systemstate/mutational.rs +++ b/fuzzers/FRET/src/systemstate/mutational.rs @@ -5,10 +5,9 @@ use core::marker::PhantomData; use std::cmp::{max, min}; use hashbrown::HashMap; -use libafl_bolts::rands::{ - StdRand, random_seed, - Rand -}; +use libafl_bolts::{rands::{ + random_seed, Rand, StdRand +}, Named}; use libafl::{ common::{HasMetadata, HasNamedMetadata}, corpus::{self, Corpus}, events::{Event, EventFirer, LogSeverity}, fuzzer::Evaluator, inputs::{HasMutatorBytes, HasTargetBytes, Input, MultipartInput}, mark_feature_time, prelude::{new_hash_feedback, CorpusId, MutationResult, Mutator, UsesInput}, stages::Stage, start_timer, state::{HasCorpus, HasRand, MaybeHasClientPerfMonitor, UsesState}, Error }; @@ -16,6 +15,7 @@ use libafl::prelude::State; use petgraph::{graph::NodeIndex, graph::{self, DiGraph}}; use crate::{time::clock::{IcHist, QEMU_ISNS_PER_USEC}, fuzzer::{DO_NUM_INTERRUPT, FIRST_INT, MAX_NUM_INTERRUPT}, systemstate::{stg::{STGFeedbackState, STGNodeMetadata}, CaptureEvent, ExecInterval, FreeRTOSSystemStateMetadata, ReducedFreeRTOSSystemState}}; use libafl::state::HasCurrentTestcase; +use std::borrow::Cow; use super::stg::{STGEdge, STGNode}; @@ -194,7 +194,7 @@ where .named_metadata_map() .get::("stgfeedbackstate") { Some(s) => s, - None => { + Option::None => { panic!("STGfeedbackstate not visible") } }; @@ -400,6 +400,97 @@ where } impl UsesState for InterruptShiftStage +where + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand, +{ + type State = Z::State; +} + + +pub fn try_worst_snippets(bytes : &[u8], fbs: &STGFeedbackState, meta: &STGNodeMetadata) -> Option> { + let mut new = false; + let mut ret = Vec::new(); + for (num,interval) in meta.intervals.iter().enumerate() { + todo!(); + } + if new {Some(ret)} else {None} +} + + +/// The default mutational stage +#[derive(Clone, Debug, Default)] +pub struct STGSnippetStage { + #[allow(clippy::type_complexity)] + phantom: PhantomData<(E, EM, Z)>, +} + +impl STGSnippetStage +where + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand, +{ + pub fn new() -> Self { + Self { phantom: PhantomData } + } +} + +impl Stage for STGSnippetStage +where + E: UsesState, + EM: UsesState, + EM: EventFirer, + Z: Evaluator, + Z::State: MaybeHasClientPerfMonitor + HasCorpus + HasRand + HasMetadata + HasNamedMetadata, + ::Input: Input, + Z::State: UsesInput>, + I: HasMutatorBytes + Default +{ + fn perform( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut Self::State, + manager: &mut EM + ) -> Result<(), Error> { + let mut myrand = StdRand::new(); + myrand.set_seed(state.rand_mut().next()); + + let current_case = state.current_testcase()?; + let old_input = current_case.input().as_ref().unwrap(); + let mut new_input = old_input.clone(); + if let Some(bytes) = old_input.parts_by_name("bytes").next() { + let new_bytes = new_input.parts_by_name("bytes").next(); + if let Some(meta) = current_case.metadata_map().get::() { + let feedbackstate = match state + .named_metadata_map() + .get::("stgfeedbackstate") { + Some(s) => s, + Option::None => { + panic!("STGfeedbackstate not visible") + } + }; + todo!(); + } + + } + Ok(()) + } + + fn restart_progress_should_run(&mut self, state: &mut Self::State) -> Result { + Ok(true) + } + + fn clear_restart_progress(&mut self, state: &mut Self::State) -> Result<(), Error> { + Ok(()) + } +} + +impl UsesState for STGSnippetStage where E: UsesState, EM: UsesState, diff --git a/fuzzers/FRET/src/systemstate/stg.rs b/fuzzers/FRET/src/systemstate/stg.rs index 5878f8c759..756a139871 100644 --- a/fuzzers/FRET/src/systemstate/stg.rs +++ b/fuzzers/FRET/src/systemstate/stg.rs @@ -1,4 +1,6 @@ +use hashbrown::HashSet; +use libafl::inputs::Input; /// Feedbacks organizing SystemStates as a graph use libafl::SerdeAny; use libafl_bolts::ownedref::OwnedMutSlice; @@ -41,6 +43,8 @@ use std::{fs::OpenOptions, io::Write}; use std::borrow::Cow; use std::ops::Deref; use std::ops::DerefMut; +use std::rc::Rc; +use petgraph::visit::EdgeRef; //============================= Data Structures #[derive(Serialize, Deserialize, Clone, Debug, Default, Hash)] @@ -83,12 +87,12 @@ impl PartialEq for STGNode { } } -#[derive(Serialize, Deserialize, Clone, Debug, Default, Hash, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)] pub struct STGEdge { - // is_interrupt: bool, pub event: CaptureEvent, - pub name: String + pub name: String, + pub worst: Option<(u64, HashSet)>, // TODO: extract bytes from input } impl STGEdge { @@ -116,6 +120,19 @@ impl STGEdge { }); short } + pub fn is_abb_end(&self) -> bool { + match self.event { + CaptureEvent::APIStart | CaptureEvent::APIEnd | CaptureEvent::ISREnd | CaptureEvent::End => true, + _ => false + } + } +} + +impl Hash for STGEdge { + fn hash(&self, state: &mut H) { + self.event.hash(state); + self.name.hash(state); + } } /// Shared Metadata for a systemstateFeedback @@ -345,6 +362,26 @@ fn get_generic_hash(input: &H) -> u64 s.finish() } +fn execinterval_to_abb_instances(trace: &Vec, read_trace: &Vec>) -> HashMap)>{ + let mut instance_time: HashMap)> = HashMap::new(); + for (_i,interval) in trace.iter().enumerate() { // Iterate intervals + // sum up execution time and accesses per ABB + let temp = interval.abb.as_ref().map(|abb| abb.instance_id).unwrap_or(usize::MAX); + match instance_time.get_mut(&temp) { + Some(x) => { + x.0 += interval.get_exec_time(); + x.1.extend(read_trace[_i].clone()); + }, + None => { + if temp != usize::MAX { + instance_time.insert(temp, (interval.get_exec_time(), read_trace[_i].clone())); + } + } + }; + } + return instance_time; +} + impl StgFeedback { pub fn new(dump_name: Option) -> Self { // Self {name: String::from("STGFeedback"), last_node_trace: None, last_edge_trace: None, last_intervals: None } @@ -362,11 +399,12 @@ impl StgFeedback { /// newly discovered node? /// side effect: /// the graph gets new nodes and edge - fn update_stg_interval(trace: &Vec, table: &HashMap, fbs: &mut STGFeedbackState) -> (Vec, Vec, bool, bool) { + fn update_stg_interval(trace: &Vec, read_trace: &Vec>, table: &HashMap, fbs: &mut STGFeedbackState) -> (Vec, Vec, bool, bool) { let mut return_node_trace = vec![fbs.entrypoint]; let mut return_edge_trace = vec![]; let mut interesting = false; let mut updated = false; + let mut instance_time = execinterval_to_abb_instances(trace, read_trace); // add all missing state+abb combinations to the graph for (_i,interval) in trace.iter().enumerate() { // Iterate intervals let node = STGNode {base: table[&interval.start_state].clone(), abb: interval.abb.as_ref().unwrap().clone()}; @@ -388,8 +426,23 @@ impl StgFeedback { let e = fbs.graph.edges_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).find(|x| petgraph::visit::EdgeRef::target(x) == next_idx); if let Some(e_) = e { return_edge_trace.push(petgraph::visit::EdgeRef::id(&e_)); + if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) { + let ref_ = &mut fbs.graph.edge_weight_mut(e_.id()).unwrap().worst; + if ref_.is_some() { + let w = ref_.as_mut().unwrap(); + if w.0 < *time {*w = (*time, accesses.clone())}; + } else { + *ref_ = Some((*time, accesses.clone())); + } + } } else { - let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone()}); + let mut e__ = STGEdge{event: interval.start_capture.0, name: interval.start_capture.1.clone(), worst: None}; + if e__.is_abb_end() { + if let Some((time,accesses)) = instance_time.get_mut(&interval.abb.as_ref().unwrap().instance_id) { + e__.worst = Some((*time, accesses.clone())); + } + } + let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], next_idx, e__); return_edge_trace.push(e_); interesting |= INTEREST_EDGE; updated = true; @@ -405,7 +458,13 @@ impl StgFeedback { } // every path terminates at the end if !fbs.graph.neighbors_directed(return_node_trace[return_node_trace.len()-1],Direction::Outgoing).any(|x| x == fbs.exitpoint) { - let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, STGEdge { event: CaptureEvent::End, name: String::from("End") }); + let mut e__ = STGEdge { event: CaptureEvent::End, name: String::from("End"), worst: None}; + if e__.is_abb_end() { + if let Some((time,accesses)) = instance_time.get_mut(&trace[trace.len()-1].abb.as_ref().unwrap().instance_id) { + e__.worst = Some((*time, accesses.clone())); + } + } + let e_ = fbs.graph.add_edge(return_node_trace[return_node_trace.len()-1], fbs.exitpoint, e__); return_edge_trace.push(e_); interesting |= INTEREST_EDGE; updated = true; @@ -453,14 +512,14 @@ where .named_metadata_map_mut() .get_mut::("stgfeedbackstate") { Some(s) => s, - None => { + Option::None => { let n=STGFeedbackState::default(); state.named_metadata_map_mut().insert("stgfeedbackstate",n); state.named_metadata_map_mut().get_mut::("stgfeedbackstate").unwrap() } }; - let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_states, feedbackstate); + let (nodetrace, edgetrace, mut interesting, mut updated) = StgFeedback::update_stg_interval(&observer.last_trace, &observer.last_reads, &observer.last_states, feedbackstate); { let h = get_generic_hash(&edgetrace); @@ -557,7 +616,7 @@ where let edges = self.last_edge_trace.take(); match nodes { Some(s) => testcase.metadata_map_mut().insert(STGNodeMetadata::new(s, edges.unwrap(), self.last_abbs_hash.take().unwrap_or_default(), self.last_aggregate_hash.take().unwrap_or_default(), self.last_top_abb_hashes.take().unwrap_or_default(), self.last_intervals.take().unwrap())), - None => (), + Option::None => (), } Ok(()) }