From 5d2e7b5bc27604e5827a9d7511d74288565abfbd Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 7 Dec 2020 18:15:35 +0100 Subject: [PATCH 1/5] started working --- afl/src/engines/mod.rs | 27 --------------------------- afl/src/executors/inmemory.rs | 11 ++--------- afl/src/executors/mod.rs | 29 +++++++++++++++++++++++++++++ afl/src/observers/mod.rs | 3 ++- 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index f734aaa7d9..6f536b636e 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -66,33 +66,6 @@ where self.metadatas_mut().insert(meta.name(), meta); } - /// Get the linked observers - fn observers(&self) -> &[Rc>]; - - /// Get the linked observers - fn observers_mut(&mut self) -> &mut Vec>>; - - /// Add a linked observer - fn add_observer(&mut self, observer: Rc>) { - self.observers_mut().push(observer); - } - - /// Reset the state of all the observes linked to this executor - fn reset_observers(&mut self) -> Result<(), AflError> { - for observer in self.observers() { - observer.borrow_mut().reset()?; - } - Ok(()) - } - - /// Run the post exec hook for all the observes linked to this executor - fn post_exec_observers(&mut self) -> Result<(), AflError> { - self.observers() - .iter() - .map(|x| x.borrow_mut().post_exec()) - .fold(Ok(()), |acc, x| if x.is_err() { x } else { acc }) - } - /// Returns vector of feebacks fn feedbacks(&self) -> &[Box>]; diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index b51f927496..6acca6b8b3 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -5,6 +5,7 @@ use core::ptr; use crate::executors::{Executor, ExitKind}; use crate::inputs::Input; +use crate::metamap::NamedAnyMap; use crate::AflError; type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; @@ -14,15 +15,7 @@ where I: Input, { harness: HarnessFunction, -} - -impl Into>> for InMemoryExecutor -where - I: Input, -{ - fn into(self) -> Rc> { - Rc::new(RefCell::new(self)) - } + observers: NamedAnyMap, } static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index 40bcafe64f..aaf98385b5 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -1,6 +1,8 @@ pub mod inmemory; use crate::inputs::Input; +use crate::observers::Observer; +use crate::metamap::NamedAnyMap; use crate::AflError; pub enum ExitKind { @@ -18,4 +20,31 @@ where { /// Instruct the target about the input and run fn run_target(&mut self, input: &I) -> Result; + + /// Get the linked observers + fn observers(&self) -> &NamedAnyMap; + + /// Get the linked observers + fn observers_mut(&mut self) -> &mut NamedAnyMap; + + /// Add a linked observer + fn add_observer(&mut self, observer: Box, name: &'static str) { + self.observers_mut().push(observer); + } + + /// Reset the state of all the observes linked to this executor + fn reset_observers(&mut self) -> Result<(), AflError> { + for observer in self.observers_mut() { + observer.reset()?; + } + Ok(()) + } + + /// Run the post exec hook for all the observes linked to this executor + fn post_exec_observers(&mut self) -> Result<(), AflError> { + self.observers_mut() + .iter() + .map(|x| x.post_exec()) + .fold(Ok(()), |acc, x| if x.is_err() { x } else { acc }) + } } diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 4db03f8d5a..f790e6a15e 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -3,13 +3,14 @@ extern crate num; use alloc::rc::Rc; use core::cell::RefCell; use core::slice::from_raw_parts_mut; +use core::any::Any; use num::Integer; use crate::AflError; /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer { +pub trait Observer: Any { fn flush(&mut self) -> Result<(), AflError> { Ok(()) } From 4e1d844b7daa2ea753a0ae30a8f8e904f6ce7349 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 7 Dec 2020 22:20:28 +0100 Subject: [PATCH 2/5] fix anymap traverse all --- afl/src/executors/inmemory.rs | 14 ++++-- afl/src/executors/mod.rs | 26 ++++++----- afl/src/feedbacks/mod.rs | 57 ++++++++++++------------ afl/src/metamap.rs | 82 ++++++++++++++++++++++++++--------- afl/src/observers/mod.rs | 53 +++++++++++++--------- 5 files changed, 147 insertions(+), 85 deletions(-) diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index 6acca6b8b3..5963a52d14 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -1,11 +1,10 @@ -use alloc::rc::Rc; -use core::cell::RefCell; use core::ffi::c_void; use core::ptr; use crate::executors::{Executor, ExitKind}; use crate::inputs::Input; use crate::metamap::NamedAnyMap; +use crate::observers::Observer; use crate::AflError; type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; @@ -15,7 +14,7 @@ where I: Input, { harness: HarnessFunction, - observers: NamedAnyMap, + observers: NamedAnyMap, } static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); @@ -35,6 +34,14 @@ where } Ok(ret) } + + fn observers(&self) -> &NamedAnyMap { + &self.observers + } + + fn observers_mut(&mut self) -> &mut NamedAnyMap { + &mut self.observers + } } impl InMemoryExecutor @@ -48,6 +55,7 @@ where } Self { harness: harness_fn, + observers: NamedAnyMap::new(), } } } diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index aaf98385b5..e17d13b146 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -1,8 +1,8 @@ pub mod inmemory; use crate::inputs::Input; -use crate::observers::Observer; use crate::metamap::NamedAnyMap; +use crate::observers::Observer; use crate::AflError; pub enum ExitKind { @@ -22,29 +22,33 @@ where fn run_target(&mut self, input: &I) -> Result; /// Get the linked observers - fn observers(&self) -> &NamedAnyMap; + fn observers(&self) -> &NamedAnyMap; /// Get the linked observers - fn observers_mut(&mut self) -> &mut NamedAnyMap; + fn observers_mut(&mut self) -> &mut NamedAnyMap; /// Add a linked observer - fn add_observer(&mut self, observer: Box, name: &'static str) { - self.observers_mut().push(observer); + fn add_observer(&mut self, observer: Box) { + self.observers_mut().insert(observer, observer.name()); } /// Reset the state of all the observes linked to this executor fn reset_observers(&mut self) -> Result<(), AflError> { - for observer in self.observers_mut() { - observer.reset()?; + for typeid in self.observers().all_typeids() { + for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() { + observer.reset()?; + } } Ok(()) } /// Run the post exec hook for all the observes linked to this executor fn post_exec_observers(&mut self) -> Result<(), AflError> { - self.observers_mut() - .iter() - .map(|x| x.post_exec()) - .fold(Ok(()), |acc, x| if x.is_err() { x } else { acc }) + for typeid in self.observers().all_typeids() { + for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() { + observer.post_exec()?; + } + } + Ok(()) } } diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index c3cb878b80..7fe07f7efd 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -7,6 +7,7 @@ use num::Integer; use serde::{Deserialize, Serialize}; use crate::corpus::{Testcase, TestcaseMetadata}; +use crate::executors::Executor; use crate::inputs::Input; use crate::observers::MapObserver; use crate::serde_anymap::SerdeAny; @@ -17,7 +18,7 @@ where I: Input, { /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) - fn is_interesting(&mut self, input: &I) -> Result; + fn is_interesting(&mut self, input: &I, executor: &dyn Executor) -> Result; /// Append to the testcase the generated metadata in case of a new corpus item fn append_metadata(&mut self, _testcase: &mut Testcase) -> Result<(), AflError> { @@ -28,6 +29,8 @@ where fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { Ok(()) } + + fn name(&self) -> &'static str; } /// A Reducer function is used to aggregate values for the novelty search @@ -78,16 +81,6 @@ where } } -/// Returns a usable history map of the given size -pub fn create_history_map(map_size: usize) -> Rc>> -where - T: Default + Clone, -{ - { - Rc::new(RefCell::new(vec![T::default(); map_size])) - } -} - /// The most common AFL-like feedback type pub struct MapFeedback where @@ -96,11 +89,11 @@ where O: MapObserver, { /// Contains information about untouched entries - history_map: Rc>>, - /// The observer this feedback struct observes - map_observer: Rc>, + history_map: Vec, + /// Name identifier of this instance + name: &'static str, /// Phantom Data of Reducer - phantom: PhantomData, + phantom: PhantomData<(R, O)>, } impl Feedback for MapFeedback @@ -110,9 +103,8 @@ where O: MapObserver, I: Input, { - fn is_interesting(&mut self, _input: &I) -> Result { + fn is_interesting(&mut self, _input: &I, executor: &dyn Executor) -> Result { let mut interesting = 0; - // TODO optimize let size = self.map_observer.borrow().map().len(); let mut history_map = self.history_map.borrow_mut(); @@ -129,6 +121,10 @@ where Ok(interesting) } + + fn name(&self) -> &'static str { + self.name + } } impl MapFeedback @@ -137,11 +133,11 @@ where R: Reducer, O: MapObserver, { - /// Create new MapFeedback using a map observer - pub fn new(map_observer: Rc>, map_size: usize) -> Self { + /// 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], + name: name, phantom: PhantomData, } } @@ -155,13 +151,10 @@ where { /// 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 { + pub fn with_history_map(name: &'static str, history_map: Vec) -> Self { Self { - map_observer: map_observer, history_map: history_map, + name: name, phantom: PhantomData, } } @@ -206,11 +199,11 @@ where O: MapObserver, { /// Contains information about untouched entries - history_map: Rc>>, - /// The observer this feedback struct observes - map_observer: Rc>, + history_map: Vec, + /// Name identifier of this instance + name: &'static str, /// Phantom Data of Reducer - phantom: PhantomData, + phantom: PhantomData<(R, O)>, /// Track novel entries indexes novelties: Vec, } @@ -254,6 +247,10 @@ where self.novelties.clear(); Ok(()) } + + fn name(&self) -> &'static str { + self.name + } } impl MapTrackerFeedback diff --git a/afl/src/metamap.rs b/afl/src/metamap.rs index 979e641fcf..42d5dc23c1 100644 --- a/afl/src/metamap.rs +++ b/afl/src/metamap.rs @@ -2,7 +2,7 @@ use alloc::boxed::Box; use alloc::vec::Vec; use core::any::{Any, TypeId}; use core::slice::{Iter, IterMut}; -use hashbrown::hash_map::{Values, ValuesMut}; +use hashbrown::hash_map::{Keys, Values, ValuesMut}; use hashbrown::HashMap; pub struct MetaMap { @@ -241,11 +241,22 @@ impl MetaInstanceMap { } } -pub struct NamedAnyMap { - map: HashMap>>, +pub trait AsAny { + fn as_any(&self) -> &dyn Any; + fn as_any_mut(&mut self) -> &mut dyn Any; } -impl NamedAnyMap { +pub struct NamedAnyMap +where + B: ?Sized + Any + AsAny, +{ + map: HashMap>>, +} + +impl NamedAnyMap +where + B: ?Sized + Any + AsAny, +{ pub fn get(&self, name: &'static str) -> Option<&T> where T: Any, @@ -254,7 +265,14 @@ impl NamedAnyMap { None => None, Some(h) => h .get(&name) - .map(|x| x.as_ref().downcast_ref::().unwrap()), + .map(|x| x.as_any().downcast_ref::().unwrap()), + } + } + + pub fn by_typeid(&self, name: &'static str, typeid: &TypeId) -> Option<&B> { + match self.map.get(typeid) { + None => None, + Some(h) => h.get(&name).map(|x| x.as_ref()), } } @@ -266,27 +284,42 @@ impl NamedAnyMap { None => None, Some(h) => h .get_mut(&name) - .map(|x| x.as_mut().downcast_mut::().unwrap()), + .map(|x| x.as_any_mut().downcast_mut::().unwrap()), + } + } + + pub fn by_typeid_mut(&mut self, name: &'static str, typeid: &TypeId) -> Option<&mut B> { + match self.map.get_mut(typeid) { + None => None, + Some(h) => h.get(&name).map(|x| x.as_mut()), } } pub fn get_all( &self, - ) -> Option>, fn(&Box) -> &T>> + ) -> Option>, fn(&Box) -> &T>> where T: Any, { match self.map.get(&TypeId::of::()) { None => None, - Some(h) => Some(h.values().map(|x| x.as_ref().downcast_ref::().unwrap())), + Some(h) => Some(h.values().map(|x| x.as_any().downcast_ref::().unwrap())), + } + } + + pub fn all_by_typeid( + &self, + typeid: &TypeId, + ) -> Option>, fn(&Box) -> &B>> { + match self.map.get(typeid) { + None => None, + Some(h) => Some(h.values().map(|x| x.as_ref())), } } pub fn get_all_mut( &mut self, - ) -> Option< - core::iter::Map>, fn(&mut Box) -> &mut T>, - > + ) -> Option>, fn(&mut Box) -> &mut T>> where T: Any, { @@ -294,23 +327,32 @@ impl NamedAnyMap { None => None, Some(h) => Some( h.values_mut() - .map(|x| x.as_mut().downcast_mut::().unwrap()), + .map(|x| x.as_any_mut().downcast_mut::().unwrap()), ), } } - pub fn insert(&mut self, t: T, name: &'static str) - where - T: Any, + pub fn all_by_typeid_mut( + &mut self, + typeid: &TypeId, + ) -> Option>, fn(&mut Box) -> &mut B>> { - let typeid = TypeId::of::(); + match self.map.get_mut(typeid) { + None => None, + Some(h) => Some(h.values_mut().map(|x| x.as_mut())), + } + } + + pub fn all_typeids(&self) -> Keys<'_, TypeId, HashMap<&'static str, Box>> { + self.map.keys() + } + + pub fn insert(&mut self, val: Box, name: &'static str) { + let typeid = val.type_id(); if !self.map.contains_key(&typeid) { self.map.insert(typeid, HashMap::default()); } - self.map - .get_mut(&typeid) - .unwrap() - .insert(name, Box::new(t)); + self.map.get_mut(&typeid).unwrap().insert(name, val); } pub fn len(&self) -> usize { diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index f790e6a15e..54ae4097e4 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -1,16 +1,15 @@ extern crate num; -use alloc::rc::Rc; -use core::cell::RefCell; -use core::slice::from_raw_parts_mut; use core::any::Any; +use core::slice::from_raw_parts_mut; use num::Integer; +use crate::metamap::AsAny; use crate::AflError; /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: Any { +pub trait Observer: Any + AsAny { fn flush(&mut self) -> Result<(), AflError> { Ok(()) } @@ -20,6 +19,8 @@ pub trait Observer: Any { fn post_exec(&mut self) -> Result<(), AflError> { Ok(()) } + + fn name(&self) -> &'static str; } /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information @@ -52,24 +53,41 @@ where } } -pub struct StdMapObserver<'a, T> +pub struct StdMapObserver where - T: Integer + Copy, + T: Integer + Copy + 'static, { - map: &'a mut [T], + map: &'static mut [T], initial: T, + name: &'static str, } -impl<'a, T> Observer for StdMapObserver<'a, T> +impl Observer for StdMapObserver where T: Integer + Copy, { fn reset(&mut self) -> Result<(), AflError> { self.reset_map() } + + fn name(&self) -> &'static str { + self.name + } } -impl<'a, T> MapObserver for StdMapObserver<'a, T> +impl AsAny for StdMapObserver +where + T: Integer + Copy, +{ + fn as_any(&self) -> &dyn Any { + self + } + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } +} + +impl MapObserver for StdMapObserver where T: Integer + Copy, { @@ -94,36 +112,29 @@ where } } -impl<'a, T> StdMapObserver<'a, T> +impl StdMapObserver where T: Integer + Copy, { /// Creates a new MapObserver - pub fn new(map: &'a mut [T]) -> Self { + pub fn new(name: &'static str, map: &'static mut [T]) -> Self { let initial = if map.len() > 0 { map[0] } else { T::zero() }; Self { map: map, initial: initial, + name: name, } } /// Creates a new MapObserver from a raw pointer - pub fn new_from_ptr(map_ptr: *mut T, len: usize) -> Self { + pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self { unsafe { let initial = if len > 0 { *map_ptr } else { T::zero() }; StdMapObserver { map: from_raw_parts_mut(map_ptr, len), initial: initial, + name: name, } } } } - -impl<'a, T> Into>> for StdMapObserver<'a, T> -where - T: Integer + Copy, -{ - fn into(self) -> Rc> { - Rc::new(RefCell::new(self)) - } -} From ff983ecf239ece937e9de3ae09f72fec2f1c1c93 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 8 Dec 2020 12:37:49 +0100 Subject: [PATCH 3/5] NamedSerdeAnyMap observers --- afl/src/engines/mod.rs | 15 +-- afl/src/executors/inmemory.rs | 10 +- afl/src/executors/mod.rs | 23 +--- afl/src/feedbacks/mod.rs | 30 ++--- afl/src/metamap.rs | 2 +- afl/src/observers/mod.rs | 37 ++++-- afl/src/serde_anymap.rs | 242 ++++++++++++++++++++++++++++++++++ 7 files changed, 295 insertions(+), 64 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index 6f536b636e..3685543e56 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -85,14 +85,15 @@ where /// Runs the input and triggers observers and feedback fn evaluate_input(&mut self, input: &I) -> Result { - self.reset_observers()?; + self.executor_mut().reset_observers()?; self.executor_mut().run_target(&input)?; self.set_executions(self.executions() + 1); - self.post_exec_observers()?; + self.executor_mut().post_exec_observers()?; let mut fitness = 0; + let observers = self.executor().observers(); for feedback in self.feedbacks_mut() { - fitness += feedback.is_interesting(&input)?; + fitness += feedback.is_interesting(&input, observers)?; } Ok(fitness) } @@ -225,14 +226,6 @@ where &mut self.metadatas } - fn observers(&self) -> &[Rc>] { - &self.observers - } - - fn observers_mut(&mut self) -> &mut Vec>> { - &mut self.observers - } - fn feedbacks(&self) -> &[Box>] { &self.feedbacks } diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index 5963a52d14..f1903b2695 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -3,7 +3,7 @@ use core::ptr; use crate::executors::{Executor, ExitKind}; use crate::inputs::Input; -use crate::metamap::NamedAnyMap; +use crate::serde_anymap::NamedSerdeAnyMap; use crate::observers::Observer; use crate::AflError; @@ -14,7 +14,7 @@ where I: Input, { harness: HarnessFunction, - observers: NamedAnyMap, + observers: NamedSerdeAnyMap, } static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); @@ -35,11 +35,11 @@ where Ok(ret) } - fn observers(&self) -> &NamedAnyMap { + fn observers(&self) -> &NamedSerdeAnyMap { &self.observers } - fn observers_mut(&mut self) -> &mut NamedAnyMap { + fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap { &mut self.observers } } @@ -55,7 +55,7 @@ where } Self { harness: harness_fn, - observers: NamedAnyMap::new(), + observers: NamedSerdeAnyMap::new(), } } } diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index e17d13b146..f71933454f 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -1,7 +1,7 @@ pub mod inmemory; use crate::inputs::Input; -use crate::metamap::NamedAnyMap; +use crate::serde_anymap::NamedSerdeAnyMap; use crate::observers::Observer; use crate::AflError; @@ -12,8 +12,6 @@ pub enum ExitKind { Timeout, } -// TODO unbox input - pub trait Executor where I: Input, @@ -22,33 +20,26 @@ where fn run_target(&mut self, input: &I) -> Result; /// Get the linked observers - fn observers(&self) -> &NamedAnyMap; + fn observers(&self) -> &NamedSerdeAnyMap; /// Get the linked observers - fn observers_mut(&mut self) -> &mut NamedAnyMap; + fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap; /// Add a linked observer fn add_observer(&mut self, observer: Box) { - self.observers_mut().insert(observer, observer.name()); + let name = observer.name(); + self.observers_mut().insert(observer, name); } /// Reset the state of all the observes linked to this executor fn reset_observers(&mut self) -> Result<(), AflError> { - for typeid in self.observers().all_typeids() { - for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() { - observer.reset()?; - } - } + self.observers_mut().for_each_mut(|_, x| Ok(x.reset()?))?; Ok(()) } /// Run the post exec hook for all the observes linked to this executor fn post_exec_observers(&mut self) -> Result<(), AflError> { - for typeid in self.observers().all_typeids() { - for observer in self.observers_mut().all_by_typeid_mut(typeid).unwrap() { - observer.post_exec()?; - } - } + self.observers_mut().for_each_mut(|_, x| Ok(x.post_exec()?))?; Ok(()) } } diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index 7fe07f7efd..e22cc25144 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -1,16 +1,11 @@ -use alloc::rc::Rc; use alloc::vec::Vec; -use core::any::Any; -use core::cell::RefCell; use core::marker::PhantomData; use num::Integer; -use serde::{Deserialize, Serialize}; use crate::corpus::{Testcase, TestcaseMetadata}; -use crate::executors::Executor; use crate::inputs::Input; -use crate::observers::MapObserver; -use crate::serde_anymap::SerdeAny; +use crate::observers::{Observer, MapObserver}; +use crate::serde_anymap::NamedSerdeAnyMap; use crate::AflError; pub trait Feedback @@ -18,7 +13,7 @@ where I: Input, { /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) - fn is_interesting(&mut self, input: &I, executor: &dyn Executor) -> Result; + fn is_interesting(&mut self, input: &I, observers: &NamedSerdeAnyMap) -> Result; /// Append to the testcase the generated metadata in case of a new corpus item fn append_metadata(&mut self, _testcase: &mut Testcase) -> Result<(), AflError> { @@ -100,21 +95,20 @@ impl Feedback for MapFeedback where T: Integer + Copy + 'static, R: Reducer, - O: MapObserver, + O: MapObserver + 'static, I: Input, { - fn is_interesting(&mut self, _input: &I, executor: &dyn Executor) -> Result { + fn is_interesting(&mut self, _input: &I, observers: &NamedSerdeAnyMap) -> 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(); + let observer = observers.get::(self.name).unwrap(); + let size = observer.map().len(); for i in 0..size { - let history = history_map[i]; + let history = self.history_map[i]; let item = observer.map()[i]; let reduced = R::reduce(history, item); if history != reduced { - history_map[i] = reduced; + self.history_map[i] = reduced; interesting += 1; } } @@ -160,6 +154,7 @@ where } } +/* #[derive(Serialize, Deserialize)] pub struct MapNoveltiesMetadata { novelties: Vec, @@ -290,9 +285,10 @@ where } } } +*/ pub type MaxMapFeedback = MapFeedback, O>; pub type MinMapFeedback = MapFeedback, O>; -pub type MaxMapTrackerFeedback = MapFeedback, O>; -pub type MinMapTrackerFeedback = MapFeedback, O>; +//pub type MaxMapTrackerFeedback = MapFeedback, O>; +//pub type MinMapTrackerFeedback = MapFeedback, O>; diff --git a/afl/src/metamap.rs b/afl/src/metamap.rs index 42d5dc23c1..dbc33500ae 100644 --- a/afl/src/metamap.rs +++ b/afl/src/metamap.rs @@ -291,7 +291,7 @@ where pub fn by_typeid_mut(&mut self, name: &'static str, typeid: &TypeId) -> Option<&mut B> { match self.map.get_mut(typeid) { None => None, - Some(h) => h.get(&name).map(|x| x.as_mut()), + Some(h) => h.get_mut(&name).map(|x| x.as_mut()), } } diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 54ae4097e4..bc9d9ac8ef 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -3,13 +3,14 @@ extern crate num; use core::any::Any; use core::slice::from_raw_parts_mut; use num::Integer; +use serde::{Deserialize, Serialize}; -use crate::metamap::AsAny; +use crate::serde_anymap::{SerdeAny, SliceMut}; use crate::AflError; /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: Any + AsAny { +pub trait Observer: SerdeAny + 'static { fn flush(&mut self) -> Result<(), AflError> { Ok(()) } @@ -35,7 +36,7 @@ where fn map_mut(&mut self) -> &mut [T]; /// Get the initial value for reset() - fn initial(&self) -> &T; + fn initial(&self) -> T; /// Get the initial value for reset() fn initial_mut(&mut self) -> &mut T; @@ -46,25 +47,27 @@ where /// Reset the map fn reset_map(&mut self) -> Result<(), AflError> { // Normal memset, see https://rust.godbolt.org/z/Trs5hv + let initial = self.initial(); for i in self.map_mut().iter_mut() { - *i = T::zero(); + *i = initial; } Ok(()) } } +#[derive(Serialize, Deserialize)] pub struct StdMapObserver where T: Integer + Copy + 'static, { - map: &'static mut [T], + map: SliceMut<'static, T>, initial: T, name: &'static str, } impl Observer for StdMapObserver where - T: Integer + Copy, + T: Integer + Copy + 'static + serde::Serialize, { fn reset(&mut self) -> Result<(), AflError> { self.reset_map() @@ -75,9 +78,9 @@ where } } -impl AsAny for StdMapObserver +impl SerdeAny for StdMapObserver where - T: Integer + Copy, + T: Integer + Copy + 'static + serde::Serialize, { fn as_any(&self) -> &dyn Any { self @@ -92,15 +95,21 @@ where T: Integer + Copy, { fn map(&self) -> &[T] { - &self.map + match &self.map { + SliceMut::Ref(r) => r, + SliceMut::Owned(v) => v.as_slice() + } } fn map_mut(&mut self) -> &mut [T] { - &mut self.map + match &mut self.map { + SliceMut::Ref(r) => r, + SliceMut::Owned(v) => v.as_mut_slice() + } } - fn initial(&self) -> &T { - &self.initial + fn initial(&self) -> T { + self.initial } fn initial_mut(&mut self) -> &mut T { @@ -120,7 +129,7 @@ where pub fn new(name: &'static str, map: &'static mut [T]) -> Self { let initial = if map.len() > 0 { map[0] } else { T::zero() }; Self { - map: map, + map: SliceMut::Ref(map), initial: initial, name: name, } @@ -131,7 +140,7 @@ where unsafe { let initial = if len > 0 { *map_ptr } else { T::zero() }; StdMapObserver { - map: from_raw_parts_mut(map_ptr, len), + map: SliceMut::Ref(from_raw_parts_mut(map_ptr, len)), initial: initial, name: name, } diff --git a/afl/src/serde_anymap.rs b/afl/src/serde_anymap.rs index 72d8bf7fd6..7d625e2693 100644 --- a/afl/src/serde_anymap.rs +++ b/afl/src/serde_anymap.rs @@ -5,6 +5,10 @@ use alloc::boxed::Box; use core::any::{Any, TypeId}; use core::default::Default; use core::fmt; +use core::slice::{Iter, IterMut}; +use hashbrown::hash_map::{Keys, Values, ValuesMut}; + +use crate::AflError; pub fn pack_type_id(id: u64) -> TypeId { unsafe { *(&id as *const u64 as *const TypeId) } @@ -199,3 +203,241 @@ impl SerdeAnyMap { } } } + +#[derive(Serialize, Deserialize)] +pub struct NamedSerdeAnyMap +where + B: ?Sized + SerdeAny, +{ + map: HashMap>>, +} + +impl NamedSerdeAnyMap +where + B: ?Sized + SerdeAny, +{ + pub fn get(&self, name: &'static str) -> Option<&T> + where + T: Any, + { + match self.map.get(&unpack_type_id(TypeId::of::())) { + None => None, + Some(h) => h + .get(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())) + .map(|x| x.as_any().downcast_ref::().unwrap()), + } + } + + pub fn by_typeid(&self, name: &'static str, typeid: &TypeId) -> Option<&B> { + match self.map.get(&unpack_type_id(*typeid)) { + None => None, + Some(h) => h.get(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())).map(|x| x.as_ref()), + } + } + + pub fn get_mut(&mut self, name: &'static str) -> Option<&mut T> + where + T: Any, + { + match self.map.get_mut(&unpack_type_id(TypeId::of::())) { + None => None, + Some(h) => h + .get_mut(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())) + .map(|x| x.as_any_mut().downcast_mut::().unwrap()), + } + } + + pub fn by_typeid_mut(&mut self, name: &'static str, typeid: &TypeId) -> Option<&mut B> { + match self.map.get_mut(&unpack_type_id(*typeid)) { + None => None, + Some(h) => h.get_mut(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())).map(|x| x.as_mut()), + } + } + + pub fn get_all( + &self, + ) -> Option>, fn(&Box) -> &T>> + where + T: Any, + { + match self.map.get(&unpack_type_id(TypeId::of::())) { + None => None, + Some(h) => Some(h.values().map(|x| x.as_any().downcast_ref::().unwrap())), + } + } + + pub fn all_by_typeid( + &self, + typeid: &TypeId, + ) -> Option>, fn(&Box) -> &B>> { + match self.map.get(&unpack_type_id(*typeid)) { + None => None, + Some(h) => Some(h.values().map(|x| x.as_ref())), + } + } + + pub fn get_all_mut( + &mut self, + ) -> Option>, fn(&mut Box) -> &mut T>> + where + T: Any, + { + match self.map.get_mut(&unpack_type_id(TypeId::of::())) { + None => None, + Some(h) => Some( + h.values_mut() + .map(|x| x.as_any_mut().downcast_mut::().unwrap()), + ), + } + } + + pub fn all_by_typeid_mut( + &mut self, + typeid: &TypeId, + ) -> Option>, fn(&mut Box) -> &mut B>> + { + match self.map.get_mut(&unpack_type_id(*typeid)) { + None => None, + Some(h) => Some(h.values_mut().map(|x| x.as_mut())), + } + } + + pub fn all_typeids(&self) -> core::iter::Map>>, fn(&u64) -> TypeId> { + self.map.keys().map(|x| pack_type_id(*x)) + } + + pub fn for_each(&self, func: fn(&TypeId, &Box) -> Result<(), AflError>) -> Result<(), AflError> { + for (id, h) in self.map.iter() { + for x in h.values() { + func(&pack_type_id(*id), x)?; + } + } + Ok(()) + } + + pub fn for_each_mut(&mut self, func: fn(&TypeId, &mut Box) -> Result<(), AflError>) -> Result<(), AflError> { + for (id, h) in self.map.iter_mut() { + for x in h.values_mut() { + func(&pack_type_id(*id), x)?; + } + } + Ok(()) + } + + pub fn insert(&mut self, val: Box, name: &'static str) { + let id = unpack_type_id(val.type_id()); + if !self.map.contains_key(&id) { + self.map.insert(id, HashMap::default()); + } + self.map.get_mut(&id).unwrap().insert(xxhash_rust::xxh3::xxh3_64(name.as_bytes()), val); + } + + pub fn len(&self) -> usize { + self.map.len() + } + + pub fn contains_type(&self) -> bool + where + T: Any, + { + self.map.contains_key(&unpack_type_id(TypeId::of::())) + } + + pub fn contains(&self, name: &'static str) -> bool + where + T: Any, + { + match self.map.get(&unpack_type_id(TypeId::of::())) { + None => false, + Some(h) => h.contains_key(&xxhash_rust::xxh3::xxh3_64(name.as_bytes())), + } + } + + pub fn new() -> Self { + Self { + map: HashMap::default(), + } + } +} + +impl Default for NamedSerdeAnyMap +where + B: ?Sized + SerdeAny, +{ + fn default() -> Self { + Self::new() + } +} + +#[derive(Serialize)] +pub enum Ptr<'a, T: 'a + ?Sized> { + Ref(&'a T), + Owned(Box), +} + +impl<'de, 'a, T: 'a + ?Sized> Deserialize<'de> for Ptr<'a, T> +where + Box: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Ptr::Owned) + } +} + +#[derive(Serialize)] +pub enum PtrMut<'a, T: 'a + ?Sized> { + Ref(&'a mut T), + Owned(Box), +} + +impl<'de, 'a, T: 'a + ?Sized> Deserialize<'de> for PtrMut<'a, T> +where + Box: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(PtrMut::Owned) + } +} + +#[derive(Serialize)] +pub enum Slice<'a, T: 'a + Sized> { + Ref(&'a [T]), + Owned(Vec), +} + +impl<'de, 'a, T: 'a + Sized> Deserialize<'de> for Slice<'a, T> +where + Vec: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(Slice::Owned) + } +} + +#[derive(Serialize)] +pub enum SliceMut<'a, T: 'a + Sized> { + Ref(&'a mut [T]), + Owned(Vec), +} + +impl<'de, 'a, T: 'a + Sized> Deserialize<'de> for SliceMut<'a, T> +where + Vec: Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(deserializer).map(SliceMut::Owned) + } +} + From de4fb23f3193df4ff27c2ad2e9d7456a0eeded8d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 8 Dec 2020 13:07:57 +0100 Subject: [PATCH 4/5] State is now a struct --- afl/src/engines/mod.rs | 356 ++++++++++++++++++----------------------- afl/src/stages/mod.rs | 7 +- 2 files changed, 161 insertions(+), 202 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index 3685543e56..b6afb8ffa9 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -19,167 +19,12 @@ use crate::stages::Stage; use crate::utils::{current_milliseconds, Rand}; use crate::AflError; -// TODO FeedbackMetadata to store histroy_map - pub trait StateMetadata: Debug { /// The name of this metadata - used to find it in the list of avaliable metadatas fn name(&self) -> &'static str; } -pub trait State -where - C: Corpus, - E: Executor, - I: Input, - R: Rand, -{ - /// Get executions - fn executions(&self) -> usize; - - /// Set executions - fn set_executions(&mut self, executions: usize); - - fn start_time(&self) -> u64; - fn set_start_time(&mut self, ms: u64); - - fn executions_over_seconds(&self) -> u64 { - let elapsed = current_milliseconds() - self.start_time(); - if elapsed == 0 { - return 0; - } - let elapsed = elapsed / 1000; - if elapsed == 0 { - 0 - } else { - (self.executions() as u64) / elapsed - } - } - - /// Get all the metadatas into an HashMap - fn metadatas(&self) -> &HashMap<&'static str, Box>; - - /// Get all the metadatas into an HashMap (mutable) - fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box>; - - /// Add a metadata - fn add_metadata(&mut self, meta: Box) { - self.metadatas_mut().insert(meta.name(), meta); - } - - /// Returns vector of feebacks - fn feedbacks(&self) -> &[Box>]; - - /// Returns vector of feebacks (mutable) - fn feedbacks_mut(&mut self) -> &mut Vec>>; - - /// Adds a feedback - fn add_feedback(&mut self, feedback: Box>) { - self.feedbacks_mut().push(feedback); - } - - /// Return the executor - fn executor(&self) -> &E; - - /// Return the executor (mutable) - fn executor_mut(&mut self) -> &mut E; - - /// Runs the input and triggers observers and feedback - fn evaluate_input(&mut self, input: &I) -> Result { - self.executor_mut().reset_observers()?; - self.executor_mut().run_target(&input)?; - self.set_executions(self.executions() + 1); - self.executor_mut().post_exec_observers()?; - - let mut fitness = 0; - let observers = self.executor().observers(); - for feedback in self.feedbacks_mut() { - fitness += feedback.is_interesting(&input, observers)?; - } - Ok(fitness) - } - - /// Resets all current feedbacks - fn discard_input(&mut self, input: &I) -> Result<(), AflError> { - // TODO: This could probably be automatic in the feedback somehow? - for feedback in self.feedbacks_mut() { - feedback.discard_metadata(input)?; - } - Ok(()) - } - - /// Creates a new testcase, appending the metadata from each feedback - fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result, AflError> { - let mut testcase = Testcase::new(input); - testcase.set_fitness(fitness); - for feedback in self.feedbacks_mut() { - feedback.append_metadata(&mut testcase)?; - } - - Ok(testcase) - } - - /// Create a testcase from this input, if it's intersting - fn testcase_if_interesting( - &mut self, - input: I, - fitness: u32, - ) -> Result>, AflError> { - if fitness > 0 { - Ok(Some(self.input_to_testcase(input, fitness)?)) - } else { - self.discard_input(&input)?; - Ok(None) - } - } - - /// Adds this input to the corpus, if it's intersting - fn add_if_interesting( - &mut self, - corpus: &mut C, - input: I, - fitness: u32, - ) -> Result, AflError> { - if fitness > 0 { - let testcase = self.input_to_testcase(input, fitness)?; - Ok(Some(corpus.add(testcase))) - } else { - self.discard_input(&input)?; - Ok(None) - } - } -} - -pub fn generate_initial_inputs( - rand: &mut R, - state: &mut S, - corpus: &mut C, - generator: &mut G, - events: &mut EM, - num: usize, -) -> Result<(), AflError> -where - S: State, - G: Generator, - C: Corpus, - E: Executor, - I: Input, - R: Rand, - EM: EventManager, -{ - for _ in 0..num { - let input = generator.generate(rand)?; - let fitness = state.evaluate_input(&input)?; - state.add_if_interesting(corpus, input, fitness)?; - events.fire(Event::LoadInitial { - sender_id: 0, - phantom: PhantomData, - })?; - } - events.process(state, corpus)?; - Ok(()) -} - -pub struct StdState +pub struct State where C: Corpus, E: Executor, @@ -196,60 +41,167 @@ where phantom: PhantomData<(C, R)>, } -impl State for StdState +impl State where C: Corpus, E: Executor, I: Input, R: Rand, { - fn executions(&self) -> usize { + /// Get executions + pub fn executions(&self) -> usize { self.executions } - fn set_executions(&mut self, executions: usize) { + /// Set executions + pub fn set_executions(&mut self, executions: usize){ self.executions = executions } - fn start_time(&self) -> u64 { + pub fn start_time(&self) -> u64{ self.start_time } - fn set_start_time(&mut self, ms: u64) { + pub fn set_start_time(&mut self, ms: u64) { self.start_time = ms } - fn metadatas(&self) -> &HashMap<&'static str, Box> { + pub fn executions_over_seconds(&self) -> u64 { + let elapsed = current_milliseconds() - self.start_time(); + if elapsed == 0 { + return 0; + } + let elapsed = elapsed / 1000; + if elapsed == 0 { + 0 + } else { + (self.executions() as u64) / elapsed + } + } + + /// Get all the metadatas into an HashMap + pub fn metadatas(&self) -> &HashMap<&'static str, Box>{ &self.metadatas } - fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box> { + /// Get all the metadatas into an HashMap (mutable) + pub fn metadatas_mut(&mut self) -> &mut HashMap<&'static str, Box>{ &mut self.metadatas } - fn feedbacks(&self) -> &[Box>] { + /// Add a metadata + pub fn add_metadata(&mut self, meta: Box) { + self.metadatas_mut().insert(meta.name(), meta); + } + + /// Returns vector of feebacks + pub fn feedbacks(&self) -> &[Box>]{ &self.feedbacks } - fn feedbacks_mut(&mut self) -> &mut Vec>> { + /// Returns vector of feebacks (mutable) + pub fn feedbacks_mut(&mut self) -> &mut Vec>>{ &mut self.feedbacks } - fn executor(&self) -> &E { - &self.executor + /// Adds a feedback + pub fn add_feedback(&mut self, feedback: Box>) { + self.feedbacks_mut().push(feedback); } - fn executor_mut(&mut self) -> &mut E { - &mut self.executor - } -} + /// Runs the input and triggers observers and feedback + pub fn evaluate_input(&mut self, input: &I, engine: &FE) -> Result + where + FE: FuzzingEngine, + EM: EventManager, + { + engine.executor_mut().reset_observers()?; + engine.executor_mut().run_target(&input)?; + self.set_executions(self.executions() + 1); + engine.executor_mut().post_exec_observers()?; + + let mut fitness = 0; + let observers = self.executor().observers(); + for feedback in self.feedbacks_mut() { + fitness += feedback.is_interesting(&input, observers)?; + } + Ok(fitness) + } + + /// Resets all current feedbacks + pub fn discard_input(&mut self, input: &I) -> Result<(), AflError> { + // TODO: This could probably be automatic in the feedback somehow? + for feedback in self.feedbacks_mut() { + feedback.discard_metadata(input)?; + } + Ok(()) + } + + /// Creates a new testcase, appending the metadata from each feedback + pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result, AflError> { + let mut testcase = Testcase::new(input); + testcase.set_fitness(fitness); + for feedback in self.feedbacks_mut() { + feedback.append_metadata(&mut testcase)?; + } + + Ok(testcase) + } + + /// Create a testcase from this input, if it's intersting + pub fn testcase_if_interesting( + &mut self, + input: I, + fitness: u32, + ) -> Result>, AflError> { + if fitness > 0 { + Ok(Some(self.input_to_testcase(input, fitness)?)) + } else { + self.discard_input(&input)?; + Ok(None) + } + } + + /// Adds this input to the corpus, if it's intersting + pub fn add_if_interesting( + &mut self, + corpus: &mut C, + input: I, + fitness: u32, + ) -> Result, AflError> { + if fitness > 0 { + let testcase = self.input_to_testcase(input, fitness)?; + Ok(Some(corpus.add(testcase))) + } else { + self.discard_input(&input)?; + Ok(None) + } + } + + pub fn generate_initial_inputs( + &mut self, + rand: &mut R, + corpus: &mut C, + generator: &mut G, + events: &mut EM, + num: usize, + ) -> Result<(), AflError> + where + G: Generator, + EM: EventManager, + { + for _ in 0..num { + let input = generator.generate(rand)?; + let fitness = self.evaluate_input(&input)?; + self.add_if_interesting(corpus, input, fitness)?; + events.fire(Event::LoadInitial { + sender_id: 0, + phantom: PhantomData, + })?; + } + events.process(self, corpus)?; + Ok(()) + } -impl StdState -where - C: Corpus, - E: Executor, - I: Input, - R: Rand, -{ pub fn new(executor: E) -> Self { Self { executions: 0, @@ -263,27 +215,38 @@ where } } -pub trait Engine +pub trait FuzzingEngine where - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, R: Rand, { - fn stages(&self) -> &[Box>]; + fn stages(&self) -> &[Box>]; - fn stages_mut(&mut self) -> &mut Vec>>; + fn stages_mut(&mut self) -> &mut Vec>>; - fn add_stage(&mut self, stage: Box>) { + fn add_stage(&mut self, stage: Box>) { self.stages_mut().push(stage); } + fn events_manager(&self) -> &EM; + + fn events_manager_mut(&mut self) -> &mut EM; + + /// Return the executor + fn executor(&self) -> &E; + + /// Return the executor (mutable) + fn executor_mut(&mut self) -> &mut E; + + // TODO additional executors, Vec>> + fn fuzz_one( &mut self, rand: &mut R, - state: &mut S, + state: &mut State, corpus: &mut C, events: &mut EM, ) -> Result { @@ -309,7 +272,7 @@ where fn fuzz_loop( &mut self, rand: &mut R, - state: &mut S, + state: &mut State, corpus: &mut C, events: &mut EM, ) -> Result<(), AflError> { @@ -329,41 +292,38 @@ where } } -pub struct StdEngine +pub struct StdFuzzingEngine where - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, R: Rand, { - stages: Vec>>, + stages: Vec>>, phantom: PhantomData, } -impl Engine for StdEngine +impl FuzzingEngine for StdFuzzingEngine where - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, R: Rand, { - fn stages(&self) -> &[Box>] { + fn stages(&self) -> &[Box>] { &self.stages } - fn stages_mut(&mut self) -> &mut Vec>> { + fn stages_mut(&mut self) -> &mut Vec>> { &mut self.stages } } -impl StdEngine +impl StdFuzzingEngine where - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index fe16267980..833edeabcd 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -9,10 +9,9 @@ use crate::inputs::Input; use crate::utils::Rand; use crate::AflError; -pub trait Stage +pub trait Stage where - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, @@ -22,7 +21,7 @@ where fn perform( &mut self, rand: &mut R, - state: &mut S, + state: &mut State, corpus: &C, events: &mut EM, input: &I, From 9111fdcf22eddae22f31363255ccb286e914d611 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 8 Dec 2020 15:12:40 +0100 Subject: [PATCH 5/5] working refactoring with observers --- afl/src/engines/mod.rs | 149 ++++++++++++++++++++++------------- afl/src/events/llmp.rs | 19 ++--- afl/src/events/mod.rs | 74 ++++++++--------- afl/src/stages/mod.rs | 6 +- afl/src/stages/mutational.rs | 45 +++++------ 5 files changed, 159 insertions(+), 134 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index b6afb8ffa9..8559fd3037 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -24,10 +24,8 @@ pub trait StateMetadata: Debug { fn name(&self) -> &'static str; } -pub struct State +pub struct State where - C: Corpus, - E: Executor, I: Input, R: Rand, { @@ -35,16 +33,12 @@ where start_time: u64, metadatas: HashMap<&'static str, Box>, // additional_corpuses: HashMap<&'static str, Box>, - observers: Vec>>, feedbacks: Vec>>, - executor: E, - phantom: PhantomData<(C, R)>, + phantom: PhantomData, } -impl State +impl State where - C: Corpus, - E: Executor, I: Input, R: Rand, { @@ -108,10 +102,13 @@ where self.feedbacks_mut().push(feedback); } + // TODO move some of these, like evaluate_input, to FuzzingEngine + /// Runs the input and triggers observers and feedback - pub fn evaluate_input(&mut self, input: &I, engine: &FE) -> Result + pub fn evaluate_input(&mut self, input: &I, engine: &mut Engine) -> Result where - FE: FuzzingEngine, + C: Corpus, + E: Executor, EM: EventManager, { engine.executor_mut().reset_observers()?; @@ -120,7 +117,7 @@ where engine.executor_mut().post_exec_observers()?; let mut fitness = 0; - let observers = self.executor().observers(); + let observers = engine.executor().observers(); for feedback in self.feedbacks_mut() { fitness += feedback.is_interesting(&input, observers)?; } @@ -162,12 +159,15 @@ where } /// Adds this input to the corpus, if it's intersting - pub fn add_if_interesting( + pub fn add_if_interesting( &mut self, corpus: &mut C, input: I, fitness: u32, - ) -> Result, AflError> { + ) -> Result, AflError> + where + C: Corpus + { if fitness > 0 { let testcase = self.input_to_testcase(input, fitness)?; Ok(Some(corpus.add(testcase))) @@ -177,45 +177,95 @@ where } } - pub fn generate_initial_inputs( + pub fn generate_initial_inputs( &mut self, rand: &mut R, corpus: &mut C, generator: &mut G, - events: &mut EM, + engine: &mut Engine, num: usize, ) -> Result<(), AflError> where G: Generator, + C: Corpus, + E: Executor, EM: EventManager, { for _ in 0..num { let input = generator.generate(rand)?; - let fitness = self.evaluate_input(&input)?; + let fitness = self.evaluate_input(&input, engine)?; self.add_if_interesting(corpus, input, fitness)?; - events.fire(Event::LoadInitial { + engine.events_manager_mut().fire(Event::LoadInitial { sender_id: 0, phantom: PhantomData, })?; } - events.process(self, corpus)?; + engine.events_manager_mut().process(self, corpus)?; Ok(()) } - pub fn new(executor: E) -> Self { + pub fn new() -> Self { Self { executions: 0, start_time: current_milliseconds(), metadatas: HashMap::default(), - observers: vec![], feedbacks: vec![], - executor: executor, phantom: PhantomData, } } } -pub trait FuzzingEngine +pub struct Engine +where + EM: EventManager, + E: Executor, + C: Corpus, + I: Input, + R: Rand, +{ + manager: EM, + executor: E, + phantom: PhantomData<(C, I, R)> +} + +impl Engine +where + EM: EventManager, + E: Executor, + C: Corpus, + I: Input, + R: Rand, +{ + pub fn events_manager(&self) -> &EM { + &self.manager + } + + pub fn events_manager_mut(&mut self) -> &mut EM { + &mut self.manager + } + + /// Return the executor + pub fn executor(&self) -> &E { + &self.executor + } + + /// Return the executor (mutable) + pub fn executor_mut(&mut self) -> &mut E { + &mut self.executor + } + + // TODO additional executors, Vec>> + + pub fn new(executor: E, events_manager: EM) -> Self { + Self { + executor: executor, + manager: events_manager, + phantom: PhantomData + } + } +} + +pub trait Fuzzer where EM: EventManager, E: Executor, @@ -231,24 +281,12 @@ where self.stages_mut().push(stage); } - fn events_manager(&self) -> &EM; - - fn events_manager_mut(&mut self) -> &mut EM; - - /// Return the executor - fn executor(&self) -> &E; - - /// Return the executor (mutable) - fn executor_mut(&mut self) -> &mut E; - - // TODO additional executors, Vec>> - fn fuzz_one( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &mut C, - events: &mut EM, + engine: &mut Engine, ) -> Result { let (testcase, idx) = corpus.next(rand)?; match testcase.input() { @@ -262,27 +300,27 @@ where let input = corpus.get(idx).input().as_ref().unwrap(); for stage in self.stages_mut() { - stage.perform(rand, state, corpus, events, &input)?; + stage.perform(rand, state, corpus, engine, &input)?; } - events.process(state, corpus)?; + engine.events_manager_mut().process(state, corpus)?; Ok(idx) } fn fuzz_loop( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &mut C, - events: &mut EM, + engine: &mut Engine, ) -> Result<(), AflError> { let mut last = current_milliseconds(); loop { - self.fuzz_one(rand, state, corpus, events)?; + self.fuzz_one(rand, state, corpus, engine)?; let cur = current_milliseconds(); if cur - last > 60 * 100 { last = cur; - events.fire(Event::UpdateStats { + engine.events_manager_mut().fire(Event::UpdateStats { sender_id: 0, new_execs: 1, phantom: PhantomData, @@ -290,9 +328,10 @@ where } } } + } -pub struct StdFuzzingEngine +pub struct StdFuzzer where EM: EventManager, E: Executor, @@ -301,10 +340,9 @@ where R: Rand, { stages: Vec>>, - phantom: PhantomData, } -impl FuzzingEngine for StdFuzzingEngine +impl Fuzzer for StdFuzzer where EM: EventManager, E: Executor, @@ -321,7 +359,7 @@ where } } -impl StdFuzzingEngine +impl StdFuzzer where EM: EventManager, E: Executor, @@ -331,12 +369,12 @@ where { pub fn new() -> Self { Self { - stages: vec![], - phantom: PhantomData, + stages: vec![] } } } + // TODO: no_std test #[cfg(feature = "std")] #[cfg(test)] @@ -348,7 +386,7 @@ mod tests { use std::io::stderr; use crate::corpus::{Corpus, InMemoryCorpus, Testcase}; - use crate::engines::{Engine, StdEngine, StdState}; + use crate::engines::{Engine, Fuzzer, StdFuzzer, State}; #[cfg(feature = "std")] use crate::events::LoggerEventManager; use crate::executors::inmemory::InMemoryExecutor; @@ -371,21 +409,22 @@ mod tests { corpus.add(testcase); let executor = InMemoryExecutor::::new(harness); - let mut state = StdState::new(executor); + let mut state = State::new(); let mut events_manager = LoggerEventManager::new(stderr()); - let mut engine = StdEngine::new(); + let mut engine = Engine::new(executor, events_manager); let mut mutator = StdScheduledMutator::new(); mutator.add_mutation(mutation_bitflip); let stage = StdMutationalStage::new(mutator); - engine.add_stage(Box::new(stage)); + let mut fuzzer = StdFuzzer::new(); + fuzzer.add_stage(Box::new(stage)); // for i in 0..1000 { - engine - .fuzz_one(&mut rand, &mut state, &mut corpus, &mut events_manager) + fuzzer + .fuzz_one(&mut rand, &mut state, &mut corpus, &mut engine) .expect(&format!("Error in iter {}", i)); } } diff --git a/afl/src/events/llmp.rs b/afl/src/events/llmp.rs index f6adf68eab..66124b4689 100644 --- a/afl/src/events/llmp.rs +++ b/afl/src/events/llmp.rs @@ -60,35 +60,33 @@ pub unsafe fn llmp_tcp_server_clientloop(client: *mut LlmpClient, _data: *mut c_ /// Eventmanager for multi-processed application #[cfg(feature = "std")] -pub struct LLMPEventManager +pub struct LLMPEventManager where - S: State, C: Corpus, I: Input, E: Executor, R: Rand, - //CE: CustomEvent, + //CE: CustomEvent, { // TODO... - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, is_broker: bool, } #[cfg(feature = "std")] -impl EventManager for LLMPEventManager +impl EventManager for LLMPEventManager where - S: State, C: Corpus, E: Executor, I: Input, R: Rand, - //CE: CustomEvent, + //CE: CustomEvent, { fn enabled(&self) -> bool { true } - fn fire(&mut self, _event: Event) -> Result<(), AflError> { + fn fire(&mut self, _event: Event) -> Result<(), AflError> { //self.events.push(event); // TODO: Serde serialize, llmp send @@ -96,7 +94,7 @@ where Ok(()) } - fn process(&mut self, _state: &mut S, _corpus: &mut C) -> Result { + fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { // TODO: iterators /* let mut handled = vec![]; @@ -127,9 +125,8 @@ where } #[cfg(feature = "std")] -impl LLMPEventManager +impl LLMPEventManager where - S: State, C: Corpus, I: Input, E: Executor, diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 42c104a693..94e9e57955 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -34,9 +34,9 @@ enum BrokerEventResult { /* /// A custom event, in case a user wants to extend the features (at compile time) -pub trait CustomEvent +pub trait CustomEvent where - S: State, + S: State, C: Corpus, E: Executor, I: Input, @@ -45,81 +45,79 @@ where /// Returns the name of this event fn name(&self) -> &str; /// This method will be called in the broker - fn handle_in_broker(&self, broker: &dyn EventManager, state: &mut S, corpus: &mut C) -> Result; + fn handle_in_broker(&self, broker: &dyn EventManager, state: &mut State, corpus: &mut C) -> Result; /// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker - fn handle_in_client(&self, client: &dyn EventManager, state: &mut S, corpus: &mut C) -> Result<(), AflError>; + fn handle_in_client(&self, client: &dyn EventManager, state: &mut State, corpus: &mut C) -> Result<(), AflError>; } struct UnusedCustomEvent {} -impl CustomEvent for UnusedCustomEvent +impl CustomEvent for UnusedCustomEvent where - S: State, + S: State, C: Corpus, E: Executor, I: Input, R: Rand, { fn name(&self) -> &str {"No custom events"} - fn handle_in_broker(&self, broker: &dyn EventManager, state: &mut S, corpus: &mut C) {Ok(BrokerEventResult::Handled)} - fn handle_in_client(&self, client: &dyn EventManager, state: &mut S, corpus: &mut C) {Ok(())} + fn handle_in_broker(&self, broker: &dyn EventManager, state: &mut State, corpus: &mut C) {Ok(BrokerEventResult::Handled)} + fn handle_in_client(&self, client: &dyn EventManager, state: &mut State, corpus: &mut C) {Ok(())} } */ /// Events sent around in the library #[derive(Serialize, Deserialize)] -pub enum Event +pub enum Event where - S: State, C: Corpus, E: Executor, I: Input, R: Rand, - // CE: CustomEvent, + // CE: CustomEvent, { LoadInitial { sender_id: u64, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, NewTestcase { sender_id: u64, testcase: Testcase, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, UpdateStats { sender_id: u64, new_execs: usize, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, Crash { sender_id: u64, input: I, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, Timeout { sender_id: u64, input: I, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, Log { sender_id: u64, severity_level: u8, message: String, - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, None { - phantom: PhantomData<(S, C, E, I, R)>, + phantom: PhantomData<(C, E, I, R)>, }, //Custom {sender_id: u64, custom_event: CE}, } -impl Event +impl Event where - S: State, C: Corpus, E: Executor, I: Input, R: Rand, - //CE: CustomEvent, + //CE: CustomEvent, { pub fn name(&self) -> &str { match self { @@ -160,7 +158,7 @@ where fn handle_in_broker( &self, - /*broker: &dyn EventManager,*/ _state: &mut S, + /*broker: &dyn EventManager,*/ _state: &mut State, _corpus: &mut C, ) -> Result { match self { @@ -215,7 +213,7 @@ where fn handle_in_client( self, - /*client: &dyn EventManager,*/ _state: &mut S, + /*client: &dyn EventManager,*/ _state: &mut State, corpus: &mut C, ) -> Result<(), AflError> { match self { @@ -236,9 +234,8 @@ where // TODO serialize and deserialize, defaults to serde } -pub trait EventManager +pub trait EventManager where - S: State, C: Corpus, E: Executor, I: Input, @@ -249,13 +246,13 @@ where fn enabled(&self) -> bool; /// Fire an Event - fn fire(&mut self, event: Event) -> Result<(), AflError>; + fn fire(&mut self, event: Event) -> Result<(), AflError>; /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process(&mut self, state: &mut S, corpus: &mut C) -> Result; + fn process(&mut self, state: &mut State, corpus: &mut C) -> Result; - fn on_recv(&self, _state: &mut S, _corpus: &mut C) -> Result<(), AflError> { + fn on_recv(&self, _state: &mut State, _corpus: &mut C) -> Result<(), AflError> { // TODO: Better way to move out of testcase, or get ref //Ok(corpus.add(self.testcase.take().unwrap())) Ok(()) @@ -263,7 +260,7 @@ where } /*TODO - fn on_recv(&self, state: &mut S, _corpus: &mut C) -> Result<(), AflError> { + fn on_recv(&self, state: &mut State, _corpus: &mut C) -> Result<(), AflError> { println!( "#{}\t exec/s: {}", state.executions(), @@ -275,41 +272,39 @@ where */ #[cfg(feature = "std")] -pub struct LoggerEventManager +pub struct LoggerEventManager where - S: State, C: Corpus, I: Input, E: Executor, R: Rand, W: Write, - //CE: CustomEvent, + //CE: CustomEvent, { - events: Vec>, + events: Vec>, writer: W, } #[cfg(feature = "std")] -impl EventManager for LoggerEventManager +impl EventManager for LoggerEventManager where - S: State, C: Corpus, E: Executor, I: Input, R: Rand, W: Write, - //CE: CustomEvent, + //CE: CustomEvent, { fn enabled(&self) -> bool { true } - fn fire(&mut self, event: Event) -> Result<(), AflError> { + fn fire(&mut self, event: Event) -> Result<(), AflError> { self.events.push(event); Ok(()) } - fn process(&mut self, state: &mut S, corpus: &mut C) -> Result { + fn process(&mut self, state: &mut State, corpus: &mut C) -> Result { // TODO: iterators let mut handled = vec![]; for x in self.events.iter() { @@ -330,9 +325,8 @@ where } #[cfg(feature = "std")] -impl LoggerEventManager +impl LoggerEventManager where - S: State, C: Corpus, I: Input, E: Executor, diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index 833edeabcd..fa11984e90 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -2,7 +2,7 @@ pub mod mutational; pub use mutational::StdMutationalStage; use crate::corpus::Corpus; -use crate::engines::State; +use crate::engines::{Engine, State}; use crate::events::EventManager; use crate::executors::Executor; use crate::inputs::Input; @@ -21,9 +21,9 @@ where fn perform( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &C, - events: &mut EM, + engine: &mut Engine, input: &I, ) -> Result<(), AflError>; } diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 9255e35714..5e323b4f20 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -5,18 +5,17 @@ use crate::executors::Executor; use crate::inputs::Input; use crate::mutators::Mutator; use crate::stages::Corpus; -use crate::stages::Stage; +use crate::stages::{Engine, Stage}; use crate::utils::Rand; use crate::AflError; use crate::{engines::State, events::Event}; // TODO multi mutators stage -pub trait MutationalStage: Stage +pub trait MutationalStage: Stage where M: Mutator, - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, @@ -38,9 +37,9 @@ where fn perform_mutational( &mut self, rand: &mut R, - state: &mut S, + state: &mut State, corpus: &C, - events: &mut EM, + engine: &mut Engine, input: &I, ) -> Result<(), AflError> { let num = self.iterations(rand); @@ -49,7 +48,7 @@ where self.mutator_mut() .mutate(rand, corpus, &mut input_mut, i as i32)?; - let fitness = state.evaluate_input(&input_mut)?; + let fitness = state.evaluate_input(&input_mut, engine)?; self.mutator_mut() .post_exec(fitness, &input_mut, i as i32)?; @@ -57,7 +56,7 @@ where let testcase_maybe = state.testcase_if_interesting(input_mut, fitness)?; if let Some(testcase) = testcase_maybe { //corpus.entries()[idx] - events.fire(Event::NewTestcase { + engine.events_manager_mut().fire(Event::NewTestcase { sender_id: 0, testcase: testcase, phantom: PhantomData, @@ -69,26 +68,24 @@ where } /// The default mutational stage -pub struct StdMutationalStage +pub struct StdMutationalStage where M: Mutator, - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, R: Rand, { mutator: M, - phantom: PhantomData<(S, EM, E, C, I, R)>, + phantom: PhantomData<(EM, E, C, I, R)>, } -impl MutationalStage - for StdMutationalStage +impl MutationalStage + for StdMutationalStage where M: Mutator, - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, @@ -105,11 +102,10 @@ where } } -impl Stage for StdMutationalStage +impl Stage for StdMutationalStage where M: Mutator, - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input, @@ -118,20 +114,19 @@ where fn perform( &mut self, rand: &mut R, - state: &mut S, + state: &mut State, corpus: &C, - events: &mut EM, + engine: &mut Engine, input: &I, ) -> Result<(), AflError> { - self.perform_mutational(rand, state, corpus, events, input) + self.perform_mutational(rand, state, corpus, engine, input) } } -impl StdMutationalStage +impl StdMutationalStage where M: Mutator, - S: State, - EM: EventManager, + EM: EventManager, E: Executor, C: Corpus, I: Input,