From b812e994a6dc123ce3d8586a7cb62fd350a1aa3f Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Mon, 19 Dec 2022 18:14:52 +0100 Subject: [PATCH] draft: add graph feedback --- fuzzers/FRET/src/systemstate/graph.rs | 578 +++++++++++++------------- fuzzers/FRET/src/systemstate/mod.rs | 2 +- 2 files changed, 294 insertions(+), 286 deletions(-) diff --git a/fuzzers/FRET/src/systemstate/graph.rs b/fuzzers/FRET/src/systemstate/graph.rs index 72698e993a..5f885a4f7e 100644 --- a/fuzzers/FRET/src/systemstate/graph.rs +++ b/fuzzers/FRET/src/systemstate/graph.rs @@ -1,16 +1,21 @@ +use libafl::SerdeAny; /// 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 libafl::prelude::HasTargetBytes; +use libafl::prelude::UsesInput; +use libafl::state::HasNamedMetadata; +use libafl::state::UsesState; 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::schedulers::MinimizerScheduler; use libafl::bolts::HasRefCnt; use libafl::bolts::AsSlice; use libafl::bolts::ownedref::OwnedSlice; @@ -33,7 +38,7 @@ use serde::{Deserialize, Serialize}; use super::RefinedFreeRTOSSystemState; use super::FreeRTOSSystemStateMetadata; -use super::observers::QemusystemstateObserver; +use super::observers::QemuSystemStateObserver; use petgraph::prelude::DiGraph; use petgraph::graph::NodeIndex; use petgraph::Direction; @@ -124,11 +129,13 @@ impl SysGraphMetadata { Self {indices: inner.iter().map(|x| x.index()).collect(), inner: inner, tcref: 0} } } -impl AsSlice for SysGraphMetadata { +impl AsSlice for SysGraphMetadata { /// Convert the slice of system-states to a slice of hashes over enumerated states fn as_slice(&self) -> &[usize] { self.indices.as_slice() } + + type Entry = usize; } impl HasRefCnt for SysGraphMetadata { @@ -143,13 +150,13 @@ impl HasRefCnt for SysGraphMetadata { libafl::impl_serdeany!(SysGraphMetadata); -pub type GraphMaximizerCorpusScheduler = - MinimizerCorpusScheduler, I, SysGraphMetadata, S>; +pub type GraphMaximizerCorpusScheduler = + MinimizerScheduler::State>,SysGraphMetadata>; //============================= Graph Feedback /// Improved System State Graph -#[derive(Serialize, Deserialize, Clone, Debug, Default)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, SerdeAny)] pub struct SysGraphFeedbackState { pub graph: DiGraph, @@ -226,7 +233,7 @@ impl Named for SysGraphFeedbackState &self.name } } -impl FeedbackState for SysGraphFeedbackState +impl SysGraphFeedbackState { fn reset(&mut self) -> Result<(), Error> { self.graph.clear(); @@ -253,28 +260,29 @@ impl SysMapFeedback { } } -impl Feedback for SysMapFeedback +impl Feedback for SysMapFeedback where - I: Input, - S: HasClientPerfMonitor + HasFeedbackStates, + S: UsesInput + HasClientPerfMonitor + HasNamedMetadata, + S::Input: HasTargetBytes, { + #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { - let observer = observers.match_name::("systemstate") + let observer = observers.match_name::("systemstate") .expect("QemusystemstateObserver not found"); let feedbackstate = state - .feedback_states_mut() - .match_name_mut::("SysMap") + .named_metadata_mut() + .get_mut::("SysMap") .unwrap(); let ret = feedbackstate.update(&observer.last_run, &observer.last_input); self.last_trace = Some(ret.1); @@ -283,7 +291,7 @@ where /// Append to the testcase the generated metadata in case of a new corpus item #[inline] - fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { let a = self.last_trace.take(); match a { Some(s) => testcase.metadata_mut().insert(SysGraphMetadata::new(s)), @@ -294,7 +302,7 @@ where /// Discard the stored metadata in case that the testcase is not added to the corpus #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.last_trace = None; Ok(()) } @@ -309,282 +317,282 @@ impl Named for SysMapFeedback //============================= Mutators //=============================== Snippets -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); +// 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, +// { +// 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.extend_from_slice(myrand.choose(c).1); - } - for i in new_input.iter().enumerate() { - input.bytes_mut()[i.0]=*i.1; - } +// 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.extend_from_slice(myrand.choose(c).1); +// } +// for i in new_input.iter().enumerate() { +// input.bytes_mut()[i.0]=*i.1; +// } - Ok(MutationResult::Mutated) - } +// Ok(MutationResult::Mutated) +// } - fn post_exec( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option - ) -> Result<(), Error> { - Ok(()) - } -} +// 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" - } -} -//=============================== Snippets -pub struct RandInputSnippetMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, -{ - phantom: PhantomData<(I, S)>, -} -impl RandInputSnippetMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, -{ - pub fn new() -> Self { - RandInputSnippetMutator{phantom: PhantomData} - } -} -impl Mutator for RandInputSnippetMutator -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); +// impl Named for RandGraphSnippetMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// fn name(&self) -> &str { +// "RandGraphSnippetMutator" +// } +// } +// //=============================== Snippets +// pub struct RandInputSnippetMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// phantom: PhantomData<(I, S)>, +// } +// impl RandInputSnippetMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// pub fn new() -> Self { +// RandInputSnippetMutator{phantom: PhantomData} +// } +// } +// impl Mutator for RandInputSnippetMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// 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"); +// 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"); - let mut collection : Vec> = Vec::new(); - let mut current_pointer : usize = 0; - for t in &trace.inner { - let node = &g[*t]; - for v in &node.variants { - if v.input == input.bytes() { - if v.input_counter > current_pointer.try_into().unwrap() { - collection.push(v.input[current_pointer..v.input_counter as usize].to_owned()); - current_pointer = v.input_counter as usize; - } - break; - } - } - } - let index_to_mutate = myrand.below(collection.len() as u64) as usize; - for i in 0..collection[index_to_mutate].len() { - collection[index_to_mutate][i] = myrand.below(0xFF) as u8; - } - for i in collection.concat().iter().enumerate() { - input.bytes_mut()[i.0]=*i.1; - } +// let mut collection : Vec> = Vec::new(); +// let mut current_pointer : usize = 0; +// for t in &trace.inner { +// let node = &g[*t]; +// for v in &node.variants { +// if v.input == input.bytes() { +// if v.input_counter > current_pointer.try_into().unwrap() { +// collection.push(v.input[current_pointer..v.input_counter as usize].to_owned()); +// current_pointer = v.input_counter as usize; +// } +// break; +// } +// } +// } +// let index_to_mutate = myrand.below(collection.len() as u64) as usize; +// for i in 0..collection[index_to_mutate].len() { +// collection[index_to_mutate][i] = myrand.below(0xFF) as u8; +// } +// for i in collection.concat().iter().enumerate() { +// input.bytes_mut()[i.0]=*i.1; +// } - Ok(MutationResult::Mutated) - } +// Ok(MutationResult::Mutated) +// } - fn post_exec( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option - ) -> Result<(), Error> { - Ok(()) - } -} +// fn post_exec( +// &mut self, +// _state: &mut S, +// _stage_idx: i32, +// _corpus_idx: Option +// ) -> Result<(), Error> { +// Ok(()) +// } +// } -impl Named for RandInputSnippetMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions + HasFeedbackStates, -{ - fn name(&self) -> &str { - "RandInputSnippetMutator" - } -} -//=============================== Suffix -pub struct RandGraphSuffixMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, -{ - phantom: PhantomData<(I, S)>, -} -impl RandGraphSuffixMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, -{ - pub fn new() -> Self { - RandGraphSuffixMutator{phantom: PhantomData} - } -} -impl Mutator for RandGraphSuffixMutator -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); +// impl Named for RandInputSnippetMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// fn name(&self) -> &str { +// "RandInputSnippetMutator" +// } +// } +// //=============================== Suffix +// pub struct RandGraphSuffixMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// phantom: PhantomData<(I, S)>, +// } +// impl RandGraphSuffixMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// pub fn new() -> Self { +// RandGraphSuffixMutator{phantom: PhantomData} +// } +// } +// impl Mutator for RandGraphSuffixMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// 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 inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter; - let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap()); - for t in trace.inner.iter().rev() { - let int_c_prefix = g[*t].base.input_counter; - if int_c_prefix < inp_c_end { - num_to_reverse-=1; - if num_to_reverse<=0 { - let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec(); - let mut ext : Vec = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect(); - new_input.append(&mut ext); - for i in new_input.iter().enumerate() { - if input.bytes_mut().len()>i.0 { - input.bytes_mut()[i.0]=*i.1; - } - else { break }; - } - break; - } - } - } - Ok(MutationResult::Mutated) - } +// 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 inp_c_end = g[*trace.inner.last().unwrap()].base.input_counter; +// let mut num_to_reverse = myrand.below(trace.inner.len().try_into().unwrap()); +// for t in trace.inner.iter().rev() { +// let int_c_prefix = g[*t].base.input_counter; +// if int_c_prefix < inp_c_end { +// num_to_reverse-=1; +// if num_to_reverse<=0 { +// let mut new_input=input.bytes()[..(int_c_prefix as usize)].to_vec(); +// let mut ext : Vec = (int_c_prefix..inp_c_end).map(|_| myrand.next().to_le_bytes()).flatten().collect(); +// new_input.append(&mut ext); +// for i in new_input.iter().enumerate() { +// if input.bytes_mut().len()>i.0 { +// input.bytes_mut()[i.0]=*i.1; +// } +// else { break }; +// } +// break; +// } +// } +// } +// Ok(MutationResult::Mutated) +// } - fn post_exec( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option - ) -> Result<(), Error> { - Ok(()) - } -} +// fn post_exec( +// &mut self, +// _state: &mut S, +// _stage_idx: i32, +// _corpus_idx: Option +// ) -> Result<(), Error> { +// Ok(()) +// } +// } -impl Named for RandGraphSuffixMutator -where - I: Input + HasBytesVec, - S: HasRand + HasMetadata + HasCorpus + HasSolutions + HasFeedbackStates, -{ - fn name(&self) -> &str { - "RandGraphSuffixMutator" - } -} \ No newline at end of file +// impl Named for RandGraphSuffixMutator +// where +// I: Input + HasBytesVec, +// S: HasRand + HasMetadata + HasCorpus + HasSolutions, +// { +// fn name(&self) -> &str { +// "RandGraphSuffixMutator" +// } +// } \ No newline at end of file diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index d85aaf3a06..6269d9cbcb 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -13,7 +13,7 @@ pub mod freertos; pub mod helpers; pub mod observers; pub mod feedbacks; -// pub mod graph; +pub mod graph; // pub mod mutators; #[cfg(feature = "fuzz_interrupt")]