From 204076bb1e75f48d2b7b19db12ed0006e40aa8a2 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 26 Feb 2021 17:11:46 +0100 Subject: [PATCH] track meta in map feedback --- libafl/src/corpus/minset.rs | 8 +- libafl/src/feedbacks/map.rs | 282 +++++++++++++++++++++++++----------- libafl/src/state/mod.rs | 9 ++ 3 files changed, 213 insertions(+), 86 deletions(-) diff --git a/libafl/src/corpus/minset.rs b/libafl/src/corpus/minset.rs index cc818c606e..8d98290c06 100644 --- a/libafl/src/corpus/minset.rs +++ b/libafl/src/corpus/minset.rs @@ -82,6 +82,7 @@ where { /// Add an entry to the corpus and return its index fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { + self.update_score(state, idx)?; self.base.on_add(state, idx) } @@ -103,6 +104,7 @@ where // TODO: IntoIter /// Gets the next entry fn next(&self, state: &mut S) -> Result { + self.cull(state)?; self.base.next(state) } } @@ -118,12 +120,16 @@ where C: Corpus, { pub fn update_score(&self, state: &mut S, idx: usize) -> Result<(), Error> { + // Create a new top rated meta if not existing + if state.metadata().get::().is_none() { + state.add_metadata(TopRatedsMetadata::new()); + } + let mut new_favoreds = vec![]; { let mut entry = state.corpus().get(idx)?.borrow_mut(); let factor = F::compute(&mut *entry)?; for elem in entry.metadatas().get::().unwrap() { - // TODO proper check for TopRatedsMetadata and create a new one if not present if let Some(old_idx) = state .metadata() .get::() diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 3914af875c..730baa4c5e 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -2,12 +2,13 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use core::{iter::IntoIterator, marker::PhantomData}; +use core::marker::PhantomData; use num::Integer; use serde::{Deserialize, Serialize}; use crate::{ bolts::tuples::Named, + corpus::Testcase, executors::ExitKind, feedbacks::Feedback, inputs::Input, @@ -73,23 +74,7 @@ where } } -/// A testcase metadata holding a list of indexes of a map -#[derive(Serialize, Deserialize)] -pub struct IndexesMetadata { - pub list: Vec, -} - -crate::impl_serdeany!(IndexesMetadata); - -impl IntoIterator for IndexesMetadata { - type Item = usize; - type IntoIter = alloc::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.list.into_iter() - } -} - +/* /// The most common AFL-like feedback type #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] @@ -203,80 +188,151 @@ where } } } +*/ -// TODO: TimeFeedback +/// A testcase metadata holding a list of indexes of a map +#[derive(Serialize, Deserialize)] +pub struct MapIndexesMetadata { + pub list: Vec, +} -/* +crate::impl_serdeany!(MapIndexesMetadata); + +impl IntoIterator for MapIndexesMetadata { + type Item = usize; + type IntoIter = alloc::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.list.into_iter() + } +} + +impl MapIndexesMetadata { + pub fn new(list: Vec) -> Self { + Self { list } + } +} + +/// A testcase metadata holding a list of indexes of a map #[derive(Serialize, Deserialize)] pub struct MapNoveltiesMetadata { - novelties: Vec, + pub list: Vec, } -impl SerdeAny for MapNoveltiesMetadata { - fn as_any(&self) -> &dyn Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn Any { - self +crate::impl_serdeany!(MapNoveltiesMetadata); + +impl IntoIterator for MapNoveltiesMetadata { + type Item = usize; + type IntoIter = alloc::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.list.into_iter() } } -impl TestcaseMetadata for MapNoveltiesMetadata { - fn name(&self) -> &'static str { - "MapNoveltiesMetadata" - } -} impl MapNoveltiesMetadata { - pub fn novelties(&self) -> &[usize] { - &self.novelties - } - - pub fn new(novelties: Vec) -> Self { - Self { - novelties: novelties, - } + pub fn new(list: Vec) -> Self { + Self { list } } } -/// The most common AFL-like feedback type that adds metadata about newly discovered entries -pub struct MapTrackerFeedback +/// The most common AFL-like feedback type +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct MapFeedback where - T: Integer + Copy + 'static, + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, R: Reducer, O: MapObserver, { /// Contains information about untouched entries history_map: Vec, + /// Indexes used in the last observation + indexes: Option>, + /// New indexes observed in the last observation + novelties: Option>, /// Name identifier of this instance - name: &'static str, + name: String, /// Phantom Data of Reducer phantom: PhantomData<(R, O)>, - /// Track novel entries indexes - novelties: Vec, } -impl Feedback for MapTrackerFeedback +impl Feedback for MapFeedback where - T: Integer + Copy + 'static, + T: Integer + + Default + + Copy + + 'static + + serde::Serialize + + serde::de::DeserializeOwned + + core::fmt::Debug, R: Reducer, O: MapObserver, I: Input, { - fn is_interesting(&mut self, _input: &I) -> Result { + fn is_interesting( + &mut self, + _input: &I, + observers: &OT, + _exit_kind: ExitKind, + ) -> Result { let mut interesting = 0; - // TODO optimize - let size = self.map_observer.borrow().map().len(); - let mut history_map = self.history_map.borrow_mut(); - let observer = self.map_observer.borrow(); - for i in 0..size { - let history = history_map[i]; - let item = observer.map()[i]; - let reduced = R::reduce(history, item); - if history != reduced { - history_map[i] = reduced; - interesting += 1; - self.novelties.push(i); + let observer = observers.match_name_type::(&self.name).unwrap(); + let size = observer.usable_count(); + let initial = observer.initial(); + + if self.indexes.is_none() && self.novelties.is_none() { + for i in 0..size { + let history = self.history_map[i]; + let item = observer.map()[i]; + + let reduced = R::reduce(history, item); + if history != reduced { + self.history_map[i] = reduced; + interesting += 1; + } + } + } else if self.indexes.is_some() && self.novelties.is_none() { + for i in 0..size { + let history = self.history_map[i]; + let item = observer.map()[i]; + if item != initial { + self.indexes.as_mut().unwrap().push(i); + } + + let reduced = R::reduce(history, item); + if history != reduced { + self.history_map[i] = reduced; + interesting += 1; + } + } + } else if self.indexes.is_none() && self.novelties.is_some() { + for i in 0..size { + let history = self.history_map[i]; + let item = observer.map()[i]; + + let reduced = R::reduce(history, item); + if history != reduced { + self.history_map[i] = reduced; + interesting += 1; + self.novelties.as_mut().unwrap().push(i); + } + } + } else { + for i in 0..size { + let history = self.history_map[i]; + let item = observer.map()[i]; + if item != initial { + self.indexes.as_mut().unwrap().push(i); + } + + let reduced = R::reduce(history, item); + if history != reduced { + self.history_map[i] = reduced; + interesting += 1; + self.novelties.as_mut().unwrap().push(i); + } } } @@ -284,57 +340,113 @@ where } fn append_metadata(&mut self, testcase: &mut Testcase) -> Result<(), Error> { - let meta = MapNoveltiesMetadata::new(core::mem::take(&mut self.novelties)); - testcase.add_metadata(meta); + match self.indexes.as_mut() { + Some(v) => { + let meta = MapIndexesMetadata::new(core::mem::take(v)); + testcase.add_metadata(meta); + } + None => {} + }; + match self.novelties.as_mut() { + Some(v) => { + let meta = MapNoveltiesMetadata::new(core::mem::take(v)); + testcase.add_metadata(meta); + } + None => {} + }; Ok(()) } /// Discard the stored metadata in case that the testcase is not added to the corpus fn discard_metadata(&mut self, _input: &I) -> Result<(), Error> { - self.novelties.clear(); + if let Some(v) = self.indexes.as_mut() { + v.clear(); + } + if let Some(v) = self.novelties.as_mut() { + v.clear(); + } Ok(()) } - - fn name(&self) -> &'static str { - self.name - } } -impl MapTrackerFeedback +impl Named for MapFeedback where - T: Integer + Copy + Default + 'static, + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, R: Reducer, O: MapObserver, { - /// Create new MapFeedback using a map observer - pub fn new(map_observer: Rc>, map_size: usize) -> Self { + #[inline] + fn name(&self) -> &str { + self.name.as_str() + } +} + +impl MapFeedback +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, + R: Reducer, + O: MapObserver + Observer, +{ + /// Create new MapFeedback + pub fn new(name: &'static str, map_size: usize) -> Self { Self { - map_observer: map_observer, - history_map: create_history_map::(map_size), + history_map: vec![T::default(); map_size], phantom: PhantomData, - novelties: vec![], + indexes: None, + novelties: None, + name: name.to_string(), + } + } + + /// Create new MapFeedback for the observer type. + pub fn new_with_observer(map_observer: &O) -> Self { + Self { + history_map: vec![T::default(); map_observer.map().len()], + phantom: PhantomData, + indexes: None, + novelties: None, + name: map_observer.name().to_string(), + } + } + + /// Create new MapFeedback specifying if it must track indexes of novelties + pub fn new_track(name: &'static str, map_size: usize, track_indexes: bool, track_novelties: bool) -> Self { + Self { + history_map: vec![T::default(); map_size], + phantom: PhantomData, + indexes: if track_indexes { Some(vec![]) } else { None }, + novelties: if track_novelties { Some(vec![]) } else { None }, + name: name.to_string(), + } + } + + /// Create new MapFeedback for the observer type if it must track indexes of novelties + pub fn new_with_observer_track(map_observer: &O, track_indexes: bool, track_novelties: bool) -> Self { + Self { + history_map: vec![T::default(); map_observer.map().len()], + phantom: PhantomData, + indexes: if track_indexes { Some(vec![]) } else { None }, + novelties: if track_novelties { Some(vec![]) } else { None }, + name: map_observer.name().to_string(), } } } -impl MapTrackerFeedback +impl MapFeedback where - T: Integer + Copy + 'static, + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, R: Reducer, O: MapObserver, { /// Create new MapFeedback using a map observer, and a map. /// The map can be shared. - pub fn with_history_map( - map_observer: Rc>, - history_map: Rc>>, - ) -> Self { - MapTrackerFeedback { - map_observer: map_observer, + pub fn with_history_map(name: &'static str, history_map: Vec) -> Self { + Self { history_map: history_map, + name: name.to_string(), + indexes: None, + novelties: None, phantom: PhantomData, - novelties: vec![], } } } -*/ diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index d82b8d4e73..b00bddd23e 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -85,6 +85,15 @@ pub trait HasMetadata { { self.metadata_mut().insert(meta); } + + /// Check for a metadata + #[inline] + fn has_metadata(&self) -> bool + where + M: SerdeAny, + { + self.metadata().get::().is_some() + } } /// Trait for elements offering a feedbacks tuple