From 6875f0073612a7d84ad0995a87882cac164bdf3a Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 15 Feb 2021 14:05:22 +0100 Subject: [PATCH] map feedback file --- afl/src/corpus/ondisk.rs | 4 +- afl/src/corpus/testcase.rs | 8 +- afl/src/feedbacks/map.rs | 323 +++++++++++++++++++++++++++++++++++++ afl/src/feedbacks/mod.rs | 318 +----------------------------------- 4 files changed, 336 insertions(+), 317 deletions(-) create mode 100644 afl/src/feedbacks/map.rs diff --git a/afl/src/corpus/ondisk.rs b/afl/src/corpus/ondisk.rs index 29ee265344..f42e1c332e 100644 --- a/afl/src/corpus/ondisk.rs +++ b/afl/src/corpus/ondisk.rs @@ -59,7 +59,9 @@ where } _ => {} } - entry.store_input().expect("Could not save testcase to disk".into()); + entry + .store_input() + .expect("Could not save testcase to disk".into()); self.entries.push(RefCell::new(entry)); self.entries.len() - 1 } diff --git a/afl/src/corpus/testcase.rs b/afl/src/corpus/testcase.rs index 3e1cbb7954..097d0b474f 100644 --- a/afl/src/corpus/testcase.rs +++ b/afl/src/corpus/testcase.rs @@ -45,8 +45,12 @@ where pub fn store_input(&mut self) -> Result { let fname; match self.filename() { - Some(f) => { fname = f.clone(); }, - None => { return Ok(false); } + Some(f) => { + fname = f.clone(); + } + None => { + return Ok(false); + } }; match self.input_mut() { None => Ok(false), diff --git a/afl/src/feedbacks/map.rs b/afl/src/feedbacks/map.rs new file mode 100644 index 0000000000..95efb72228 --- /dev/null +++ b/afl/src/feedbacks/map.rs @@ -0,0 +1,323 @@ +use alloc::{ + string::{String, ToString}, + vec::Vec, +}; +use core::marker::PhantomData; +use num::Integer; +use serde::{Deserialize, Serialize}; + +use crate::{ + bolts::tuples::Named, + executors::ExitKind, + feedbacks::Feedback, + inputs::Input, + observers::{MapObserver, Observer, ObserversTuple}, + AflError, +}; + +pub type MaxMapFeedback = MapFeedback, O>; +pub type MinMapFeedback = MapFeedback, O>; + +//pub type MaxMapTrackerFeedback = MapFeedback, O>; +//pub type MinMapTrackerFeedback = MapFeedback, O>; + +/// A Reducer function is used to aggregate values for the novelty search +pub trait Reducer: Serialize + serde::de::DeserializeOwned + 'static +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + fn reduce(first: T, second: T) -> T; +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MaxReducer +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + phantom: PhantomData, +} + +impl Reducer for MaxReducer +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn reduce(first: T, second: T) -> T { + if first > second { + first + } else { + second + } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinReducer +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + phantom: PhantomData, +} + +impl Reducer for MinReducer +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn reduce(first: T, second: T) -> T { + if first < second { + first + } else { + second + } + } +} + +/// The most common AFL-like feedback type +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct MapFeedback +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, + R: Reducer, + O: MapObserver, +{ + /// Contains information about untouched entries + history_map: Vec, + /// Name identifier of this instance + name: String, + /// Phantom Data of Reducer + phantom: PhantomData<(R, O)>, +} + +impl Feedback for MapFeedback +where + 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, + observers: &OT, + _exit_kind: ExitKind, + ) -> Result { + let mut interesting = 0; + // TODO optimize + let observer = observers.match_name_type::(&self.name).unwrap(); + let size = observer.usable_count(); + //println!("count: {:?}, map: {:?}, history: {:?}", size, observer.map(), &self.history_map); + 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; + } + } + + //println!("..interesting: {:?}, new_history: {:?}\n", interesting, &self.history_map); + //std::thread::sleep(std::time::Duration::from_millis(100)); + + Ok(interesting) + } +} + +impl Named for MapFeedback +where + T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, + R: Reducer, + O: MapObserver, +{ + #[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 { + history_map: vec![T::default(); map_size], + phantom: PhantomData, + name: name.to_string(), + } + } + + /// Create new MapFeedback for the observer type. + /// Name should match that of the observer. + pub fn new_with_observer(name: &'static str, map_observer: &O) -> Self { + debug_assert_eq!(name, map_observer.name()); + Self { + history_map: vec![T::default(); map_observer.map().len()], + phantom: PhantomData, + name: name.to_string(), + } + } +} + +impl MapFeedback +where + 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(name: &'static str, history_map: Vec) -> Self { + Self { + history_map: history_map, + name: name.to_string(), + phantom: PhantomData, + } + } +} + +// TODO: TimeFeedback + +/* +#[derive(Serialize, Deserialize)] +pub struct MapNoveltiesMetadata { + novelties: Vec, +} + +impl SerdeAny for MapNoveltiesMetadata { + fn as_any(&self) -> &dyn Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + +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, + } + } +} + +/// The most common AFL-like feedback type that adds metadata about newly discovered entries +pub struct MapTrackerFeedback +where + T: Integer + Copy + 'static, + R: Reducer, + O: MapObserver, +{ + /// Contains information about untouched entries + history_map: Vec, + /// Name identifier of this instance + name: &'static str, + /// Phantom Data of Reducer + phantom: PhantomData<(R, O)>, + /// Track novel entries indexes + novelties: Vec, +} + +impl Feedback for MapTrackerFeedback +where + T: Integer + Copy + 'static, + R: Reducer, + O: MapObserver, + I: Input, +{ + fn is_interesting(&mut self, _input: &I) -> 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); + } + } + + Ok(interesting) + } + + fn append_metadata(&mut self, testcase: &mut Testcase) -> Result<(), AflError> { + let meta = MapNoveltiesMetadata::new(core::mem::take(&mut self.novelties)); + testcase.add_metadata(meta); + Ok(()) + } + + /// Discard the stored metadata in case that the testcase is not added to the corpus + fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { + self.novelties.clear(); + Ok(()) + } + + fn name(&self) -> &'static str { + self.name + } +} + +impl MapTrackerFeedback +where + T: Integer + Copy + Default + 'static, + R: Reducer, + O: MapObserver, +{ + /// Create new MapFeedback using a map observer + pub fn new(map_observer: Rc>, map_size: usize) -> Self { + Self { + map_observer: map_observer, + history_map: create_history_map::(map_size), + phantom: PhantomData, + novelties: vec![], + } + } +} + +impl MapTrackerFeedback +where + T: Integer + Copy + 'static, + 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, + history_map: history_map, + phantom: PhantomData, + novelties: vec![], + } + } +} +*/ diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index b4872e8e4c..f69e017f1a 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -1,12 +1,9 @@ //! The feedbacks reduce observer state after each run to a single `is_interesting`-value. //! If a testcase is interesting, it may be added to a Corpus. -use alloc::{ - string::{String, ToString}, - vec::Vec, -}; -use core::marker::PhantomData; -use num::Integer; +pub mod map; +pub use map::*; + use serde::{Deserialize, Serialize}; use crate::{ @@ -14,16 +11,10 @@ use crate::{ corpus::Testcase, executors::ExitKind, inputs::Input, - observers::{MapObserver, Observer, ObserversTuple}, + observers::ObserversTuple, AflError, }; -pub type MaxMapFeedback = MapFeedback, O>; -pub type MinMapFeedback = MapFeedback, O>; - -//pub type MaxMapTrackerFeedback = MapFeedback, O>; -//pub type MinMapTrackerFeedback = MapFeedback, O>; - /// Feedbacks evaluate the observers. /// Basically, they reduce the information provided by an observer to a value, /// indicating the "interestingness" of the last run. @@ -200,304 +191,3 @@ impl CrashFeedback { Self {} } } - -/// A Reducer function is used to aggregate values for the novelty search -pub trait Reducer: Serialize + serde::de::DeserializeOwned + 'static -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, -{ - fn reduce(first: T, second: T) -> T; -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct MaxReducer -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, -{ - phantom: PhantomData, -} - -impl Reducer for MaxReducer -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn reduce(first: T, second: T) -> T { - if first > second { - first - } else { - second - } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct MinReducer -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, -{ - phantom: PhantomData, -} - -impl Reducer for MinReducer -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, -{ - #[inline] - fn reduce(first: T, second: T) -> T { - if first < second { - first - } else { - second - } - } -} - -/// The most common AFL-like feedback type -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -pub struct MapFeedback -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, - R: Reducer, - O: MapObserver, -{ - /// Contains information about untouched entries - history_map: Vec, - /// Name identifier of this instance - name: String, - /// Phantom Data of Reducer - phantom: PhantomData<(R, O)>, -} - -impl Feedback for MapFeedback -where - 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, - observers: &OT, - _exit_kind: ExitKind, - ) -> Result { - let mut interesting = 0; - // TODO optimize - let observer = observers.match_name_type::(&self.name).unwrap(); - let size = observer.usable_count(); - //println!("count: {:?}, map: {:?}, history: {:?}", size, observer.map(), &self.history_map); - 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; - } - } - - //println!("..interesting: {:?}, new_history: {:?}\n", interesting, &self.history_map); - //std::thread::sleep(std::time::Duration::from_millis(100)); - - Ok(interesting) - } -} - -impl Named for MapFeedback -where - T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, - R: Reducer, - O: MapObserver, -{ - #[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 { - history_map: vec![T::default(); map_size], - phantom: PhantomData, - name: name.to_string(), - } - } - - /// Create new MapFeedback for the observer type. - /// Name should match that of the observer. - pub fn new_with_observer(name: &'static str, map_observer: &O) -> Self { - debug_assert_eq!(name, map_observer.name()); - Self { - history_map: vec![T::default(); map_observer.map().len()], - phantom: PhantomData, - name: name.to_string(), - } - } -} - -impl MapFeedback -where - 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(name: &'static str, history_map: Vec) -> Self { - Self { - history_map: history_map, - name: name.to_string(), - phantom: PhantomData, - } - } -} - -// TODO: TimeFeedback - -/* -#[derive(Serialize, Deserialize)] -pub struct MapNoveltiesMetadata { - novelties: Vec, -} - -impl SerdeAny for MapNoveltiesMetadata { - fn as_any(&self) -> &dyn Any { - self - } - fn as_any_mut(&mut self) -> &mut dyn Any { - self - } -} - -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, - } - } -} - -/// The most common AFL-like feedback type that adds metadata about newly discovered entries -pub struct MapTrackerFeedback -where - T: Integer + Copy + 'static, - R: Reducer, - O: MapObserver, -{ - /// Contains information about untouched entries - history_map: Vec, - /// Name identifier of this instance - name: &'static str, - /// Phantom Data of Reducer - phantom: PhantomData<(R, O)>, - /// Track novel entries indexes - novelties: Vec, -} - -impl Feedback for MapTrackerFeedback -where - T: Integer + Copy + 'static, - R: Reducer, - O: MapObserver, - I: Input, -{ - fn is_interesting(&mut self, _input: &I) -> 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); - } - } - - Ok(interesting) - } - - fn append_metadata(&mut self, testcase: &mut Testcase) -> Result<(), AflError> { - let meta = MapNoveltiesMetadata::new(core::mem::take(&mut self.novelties)); - testcase.add_metadata(meta); - Ok(()) - } - - /// Discard the stored metadata in case that the testcase is not added to the corpus - fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { - self.novelties.clear(); - Ok(()) - } - - fn name(&self) -> &'static str { - self.name - } -} - -impl MapTrackerFeedback -where - T: Integer + Copy + Default + 'static, - R: Reducer, - O: MapObserver, -{ - /// Create new MapFeedback using a map observer - pub fn new(map_observer: Rc>, map_size: usize) -> Self { - Self { - map_observer: map_observer, - history_map: create_history_map::(map_size), - phantom: PhantomData, - novelties: vec![], - } - } -} - -impl MapTrackerFeedback -where - T: Integer + Copy + 'static, - 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, - history_map: history_map, - phantom: PhantomData, - novelties: vec![], - } - } -} -*/