diff --git a/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs b/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs index a4b05b9be5..c67d2db867 100644 --- a/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs +++ b/fuzzers/wcet_qemu_sys/src/bin/fuzzer.rs @@ -1,5 +1,6 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. +use wcet_qemu_sys::sysstate::graph::RandGraphSnippetMutator; use wcet_qemu_sys::sysstate::graph::GraphMaximizerCorpusScheduler; use wcet_qemu_sys::sysstate::graph::SysMapFeedback; use wcet_qemu_sys::sysstate::graph::SysGraphFeedbackState; @@ -391,7 +392,10 @@ fn fuzz( // let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); // Setup a MOPT mutator - let mutator = StdMOptMutator::new(&mut state, havoc_mutations().merge(tokens_mutations()), 5)?; + let mutator = StdMOptMutator::new(&mut state, havoc_mutations() + .merge(tokens_mutations()) + .merge(tuple_list!(RandGraphSnippetMutator::new())), + 5)?; // let power = PowerMutationalStage::new(mutator, PowerSchedule::FAST, &edges_observer); let mutation = StdMutationalStage::new(mutator); diff --git a/fuzzers/wcet_qemu_sys/src/sysstate/graph.rs b/fuzzers/wcet_qemu_sys/src/sysstate/graph.rs index 418e4a9954..1c495526a2 100644 --- a/fuzzers/wcet_qemu_sys/src/sysstate/graph.rs +++ b/fuzzers/wcet_qemu_sys/src/sysstate/graph.rs @@ -1,5 +1,14 @@ /// Feedbacks organizing SystemStates as a graph +use libafl::inputs::HasBytesVec; +use libafl::bolts::rands::RandomSeed; +use libafl::bolts::rands::StdRand; +use libafl::mutators::Mutator; +use libafl::mutators::MutationResult; +use core::marker::PhantomData; +use libafl::state::HasCorpus; +use libafl::state::HasSolutions; +use libafl::state::HasRand; use crate::worst::MaxExecsLenFavFactor; use libafl::corpus::MinimizerCorpusScheduler; use libafl::bolts::HasRefCnt; @@ -32,6 +41,10 @@ use petgraph::graph::NodeIndex; use petgraph::Direction; use std::cmp::Ordering; +use libafl::bolts::rands::Rand; +use rand::SeedableRng; +use rand::seq::SliceRandom; + //============================= Data Structures #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] struct VariantTuple @@ -100,12 +113,13 @@ impl PartialEq for SysGraphNode { // Wrapper around Vec to attach as Metadata #[derive(Debug, Default, Serialize, Deserialize, Clone)] pub struct SysGraphMetadata { - indices: Vec, // Hashed enumeration of States + inner: Vec, + indices: Vec, tcref: isize, } impl SysGraphMetadata { pub fn new(inner: Vec) -> Self{ - Self {indices: inner.into_iter().map(|x| x.index()).collect(), tcref: 0} + Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0} } } impl AsSlice for SysGraphMetadata { @@ -277,4 +291,107 @@ impl Named for SysMapFeedback fn name(&self) -> &str { &self.name } +} + +//============================= Mutators + +pub struct RandGraphSnippetMutator +where + I: Input + HasBytesVec, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, +{ + phantom: PhantomData<(I, S)>, +} +impl RandGraphSnippetMutator +where + I: Input + HasBytesVec, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, +{ + pub fn new() -> Self { + RandGraphSnippetMutator{phantom: PhantomData} + } +} +impl Mutator for RandGraphSnippetMutator +where + I: Input + HasBytesVec, + S: HasRand + HasMetadata + HasCorpus + HasSolutions + HasFeedbackStates, +{ + fn mutate( + &mut self, + state: &mut S, + input: &mut I, + _stage_idx: i32 + ) -> Result + { + // need our own random generator, because borrowing rules + let mut myrand = StdRand::new(); + let tmp = &mut state.rand_mut(); + myrand.set_seed(tmp.next()); + drop(tmp); + + let feedbackstate = state + .feedback_states() + .match_name::("SysMap") + .unwrap(); + let g = &feedbackstate.graph; + let tmp = state.metadata().get::(); + if tmp.is_none() { // if there are no metadata it was probably not interesting anyways + return Ok(MutationResult::Skipped); + } + let trace =tmp.expect("SysGraphMetadata not found"); + // follow the path, extract snippets from last reads, find common snippets. + // those are likley keys parts. choose random parts from other sibling traces + let sibling_inputs : Vec<&Vec>= g[*trace.inner.last().unwrap()].variants.iter().map(|x| &x.input).collect(); + let mut snippet_collector = vec![]; + let mut per_input_counters = HashMap::<&Vec,usize>::new(); // ugly workaround to track multiple inputs + for t in &trace.inner { + let node = &g[*t]; + let mut per_node_snippets = HashMap::<&Vec,&[u8]>::new(); + for v in &node.variants { + match per_input_counters.get_mut(&v.input) { + None => { + if sibling_inputs.iter().any(|x| *x==&v.input) { // only collect info about siblin inputs from target + per_input_counters.insert(&v.input, v.input_counter.try_into().unwrap()); + } + }, + Some(x) => { + let x_u = *x; + if x_u = vec![]; + for c in snippet_collector { + new_input.clone_from_slice(myrand.choose(c).1); + } + for i in new_input.iter().enumerate() { + input.bytes_mut()[i.0]=*i.1; + } + + Ok(MutationResult::Mutated) + } + + fn post_exec( + &mut self, + _state: &mut S, + _stage_idx: i32, + _corpus_idx: Option + ) -> Result<(), Error> { + Ok(()) + } +} + +impl Named for RandGraphSnippetMutator +where + I: Input + HasBytesVec, + S: HasRand + HasMetadata + HasCorpus + HasSolutions + HasFeedbackStates, +{ + fn name(&self) -> &str { + "RandGraphSnippetMutator" + } } \ No newline at end of file