From 63a83a70ffce5a07c1fc9facf3dc19f3004da080 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 5 Nov 2020 10:43:28 +0100 Subject: [PATCH] import dominik map feedback --- src/corpus/mod.rs | 146 ++++++++++++++++++++++++++++++-------- src/corpus/testcase.rs | 12 +++- src/engines/aflengine.rs | 5 +- src/engines/mod.rs | 14 ++-- src/executors/inmemory.rs | 40 ++++++++--- src/executors/mod.rs | 7 +- src/feedbacks/mod.rs | 142 +++++++++++++++++++++++++----------- src/inputs/bytes.rs | 4 +- src/inputs/mod.rs | 6 +- src/lib.rs | 2 +- src/mutators/mod.rs | 14 ++-- src/mutators/scheduled.rs | 128 ++++++++++++++++++++++++++------- src/observers/mod.rs | 6 +- src/stages/mod.rs | 14 ++-- src/stages/mutational.rs | 64 ++++++++++++----- src/utils.rs | 2 +- 16 files changed, 450 insertions(+), 156 deletions(-) diff --git a/src/corpus/mod.rs b/src/corpus/mod.rs index 0715a68096..5fdf232020 100644 --- a/src/corpus/mod.rs +++ b/src/corpus/mod.rs @@ -1,16 +1,19 @@ pub mod testcase; pub use testcase::{Testcase, TestcaseMetadata}; -use crate::utils::{Rand, HasRand}; use crate::inputs::Input; +use crate::utils::{HasRand, Rand}; use crate::AflError; -use std::path::PathBuf; -use std::marker::PhantomData; use std::cell::RefCell; +use std::marker::PhantomData; +use std::path::PathBuf; use std::rc::Rc; -pub trait HasEntriesVec where I: Input { +pub trait HasEntriesVec +where + I: Input, +{ /// Get the entries vector field fn entries(&self) -> &Vec>>>; @@ -19,7 +22,10 @@ pub trait HasEntriesVec where I: Input { } /// Corpus with all current testcases -pub trait Corpus : HasEntriesVec + HasRand where I: Input { +pub trait Corpus: HasEntriesVec + HasRand +where + I: Input, +{ /// Returns the number of elements fn count(&self) -> usize { self.entries().len() @@ -37,7 +43,8 @@ pub trait Corpus : HasEntriesVec + HasRand where I: Input { let mut found = false; for x in self.entries() { i = i + 1; - if &*x.borrow() as *const _ == entry as *const _ { // TODO check if correct + if &*x.borrow() as *const _ == entry as *const _ { + // TODO check if correct found = true; break; } @@ -61,21 +68,33 @@ pub trait Corpus : HasEntriesVec + HasRand where I: Input { } } -pub struct InMemoryCorpus<'a, I, R> where I: Input, R: Rand { +pub struct InMemoryCorpus<'a, I, R> +where + I: Input, + R: Rand, +{ rand: &'a mut R, - entries: Vec>>> + entries: Vec>>>, } -impl HasEntriesVec for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { +impl HasEntriesVec for InMemoryCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ fn entries(&self) -> &Vec>>> { &self.entries } - fn entries_mut(&mut self) -> &mut Vec>>>{ + fn entries_mut(&mut self) -> &mut Vec>>> { &mut self.entries } } -impl HasRand for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { +impl HasRand for InMemoryCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ type R = R; fn rand(&self) -> &Self::R { @@ -86,11 +105,19 @@ impl HasRand for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { } } -impl Corpus for InMemoryCorpus<'_, I, R> where I: Input, R: Rand { +impl Corpus for InMemoryCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ // Just use the default implementation } -impl<'a, I, R> InMemoryCorpus<'a, I, R> where I: Input, R: Rand { +impl<'a, I, R> InMemoryCorpus<'a, I, R> +where + I: Input, + R: Rand, +{ pub fn new(rand: &'a mut R) -> Self { InMemoryCorpus { rand: rand, @@ -99,22 +126,34 @@ impl<'a, I, R> InMemoryCorpus<'a, I, R> where I: Input, R: Rand { } } -pub struct OnDiskCorpus<'a, I, R> where I: Input, R: Rand { +pub struct OnDiskCorpus<'a, I, R> +where + I: Input, + R: Rand, +{ rand: &'a mut R, entries: Vec>>>, dir_path: PathBuf, } -impl HasEntriesVec for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { +impl HasEntriesVec for OnDiskCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ fn entries(&self) -> &Vec>>> { &self.entries } - fn entries_mut(&mut self) -> &mut Vec>>>{ + fn entries_mut(&mut self) -> &mut Vec>>> { &mut self.entries } } -impl HasRand for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { +impl HasRand for OnDiskCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ type R = R; fn rand(&self) -> &Self::R { @@ -125,7 +164,11 @@ impl HasRand for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { } } -impl Corpus for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { +impl Corpus for OnDiskCorpus<'_, I, R> +where + I: Input, + R: Rand, +{ /// Add an entry and save it to disk fn add(&mut self, entry: Rc>>) { if *entry.borrow().filename() == None { @@ -140,7 +183,11 @@ impl Corpus for OnDiskCorpus<'_, I, R> where I: Input, R: Rand { // TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus } -impl<'a, I, R> OnDiskCorpus<'a, I, R> where I: Input, R: Rand { +impl<'a, I, R> OnDiskCorpus<'a, I, R> +where + I: Input, + R: Rand, +{ pub fn new(rand: &'a mut R, dir_path: PathBuf) -> Self { OnDiskCorpus { dir_path: dir_path, @@ -151,23 +198,35 @@ impl<'a, I, R> OnDiskCorpus<'a, I, R> where I: Input, R: Rand { } /// A Queue-like corpus, wrapping an existing Corpus instance -pub struct QueueCorpus where I: Input, C: Corpus { +pub struct QueueCorpus +where + I: Input, + C: Corpus, +{ corpus: C, phantom: PhantomData, pos: usize, cycles: u64, } -impl<'a, I, C> HasEntriesVec for QueueCorpus where I: Input, C: Corpus { +impl<'a, I, C> HasEntriesVec for QueueCorpus +where + I: Input, + C: Corpus, +{ fn entries(&self) -> &Vec>>> { self.corpus.entries() } - fn entries_mut(&mut self) -> &mut Vec>>>{ + fn entries_mut(&mut self) -> &mut Vec>>> { self.corpus.entries_mut() } } -impl<'a, I, C> HasRand for QueueCorpus where I: Input, C: Corpus { +impl<'a, I, C> HasRand for QueueCorpus +where + I: Input, + C: Corpus, +{ type R = C::R; fn rand(&self) -> &Self::R { @@ -178,7 +237,11 @@ impl<'a, I, C> HasRand for QueueCorpus where I: Input, C: Corpus { } } -impl<'a, I, C> Corpus for QueueCorpus where I: Input, C: Corpus { +impl<'a, I, C> Corpus for QueueCorpus +where + I: Input, + C: Corpus, +{ /// Returns the number of elements fn count(&self) -> usize { self.corpus.count() @@ -212,7 +275,11 @@ impl<'a, I, C> Corpus for QueueCorpus where I: Input, C: Corpus { } } -impl<'a, I, C> QueueCorpus where I: Input, C: Corpus { +impl<'a, I, C> QueueCorpus +where + I: Input, + C: Corpus, +{ pub fn new(corpus: C) -> Self { QueueCorpus:: { corpus: corpus, @@ -234,13 +301,13 @@ impl<'a, I, C> QueueCorpus where I: Input, C: Corpus { #[cfg(test)] mod tests { use crate::corpus::Corpus; - use crate::corpus::{QueueCorpus, OnDiskCorpus}; use crate::corpus::Testcase; + use crate::corpus::{OnDiskCorpus, QueueCorpus}; use crate::inputs::bytes::BytesInput; use crate::utils::Xoshiro256StarRand; - use std::path::PathBuf; use std::cell::RefCell; + use std::path::PathBuf; use std::rc::Rc; #[test] @@ -249,10 +316,29 @@ mod tests { let mut rand = Xoshiro256StarRand::new(); let mut q = QueueCorpus::new(OnDiskCorpus::new(&mut rand, PathBuf::from("fancy/path"))); let i = BytesInput::new(vec![0; 4]); - let t = Rc::new(RefCell::new(Testcase::new_with_filename(i, PathBuf::from("fancyfile")))); + let t = Rc::new(RefCell::new(Testcase::new_with_filename( + i, + PathBuf::from("fancyfile"), + ))); q.add(t); - let filename = q.get().unwrap().borrow().filename().as_ref().unwrap().to_owned(); - assert_eq!(filename, q.get().unwrap().borrow().filename().as_ref().unwrap().to_owned()); + let filename = q + .get() + .unwrap() + .borrow() + .filename() + .as_ref() + .unwrap() + .to_owned(); + assert_eq!( + filename, + q.get() + .unwrap() + .borrow() + .filename() + .as_ref() + .unwrap() + .to_owned() + ); assert_eq!(filename, PathBuf::from("fancy/path/fancyfile")); } } diff --git a/src/corpus/testcase.rs b/src/corpus/testcase.rs index 44d4d30718..83a23578f7 100644 --- a/src/corpus/testcase.rs +++ b/src/corpus/testcase.rs @@ -29,19 +29,25 @@ pub trait TestcaseTrait { */ #[derive(Default)] -pub struct Testcase where I: Input { +pub struct Testcase +where + I: Input, +{ input: Option, // TODO remove box filename: Option, metadatas: HashMap>, } -impl Testcase where I: Input { +impl Testcase +where + I: Input, +{ /// Make sure to return a valid input instance loading it from disk if not in memory pub fn load_input(&mut self) -> Result<&I, AflError> { // TODO: Implement cache to disk match self.input.as_ref() { Some(i) => Ok(i), - None => Err(AflError::NotImplemented("load_input".to_string())) + None => Err(AflError::NotImplemented("load_input".to_string())), } } diff --git a/src/engines/aflengine.rs b/src/engines/aflengine.rs index 5722d7cd6e..f75057281e 100644 --- a/src/engines/aflengine.rs +++ b/src/engines/aflengine.rs @@ -1,12 +1,13 @@ use std::time; use crate::engines::Engine; -use crate::inputs::Input; use crate::executors::Executor; use crate::feedbacks::Feedback; +use crate::inputs::Input; use crate::monitors::Monitor; use crate::stages::Stage; use crate::utils::Rand; + /* pub struct AflEngine<'a, I: Input> { pub rand: &'a mut dyn Rand, @@ -27,4 +28,4 @@ pub struct AflEngine<'a, I: Input> { } impl Engine<'_> for AflEngine<'_, I> {} -*/ \ No newline at end of file +*/ diff --git a/src/engines/mod.rs b/src/engines/mod.rs index ba01edd530..415dab106a 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -1,14 +1,16 @@ pub mod aflengine; -use crate::AflError; -use crate::inputs::Input; use crate::corpus::testcase::Testcase; +use crate::inputs::Input; +use crate::AflError; use std::cell::RefCell; use std::rc::Rc; -pub trait Engine<'a, I> where I: Input { - - fn execute(&mut self, input: &mut I, entry: Rc>>) -> Result; - +pub trait Engine<'a, I> +where + I: Input, +{ + fn execute(&mut self, input: &mut I, entry: Rc>>) + -> Result; } diff --git a/src/executors/inmemory.rs b/src/executors/inmemory.rs index b6e8c8c0c3..ed986ebbda 100644 --- a/src/executors/inmemory.rs +++ b/src/executors/inmemory.rs @@ -4,12 +4,15 @@ use crate::AflError; use crate::executors::{Executor, ExitKind}; -use std::ptr; use std::os::raw::c_void; +use std::ptr; type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; -pub struct InMemoryExecutor where I: Input { +pub struct InMemoryExecutor +where + I: Input, +{ cur_input: Option>, observers: Vec>, harness: HarnessFunction, @@ -17,7 +20,10 @@ pub struct InMemoryExecutor where I: Input { static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); -impl Executor for InMemoryExecutor where I: Input { +impl Executor for InMemoryExecutor +where + I: Input, +{ fn run_target(&mut self) -> Result { let bytes = match self.cur_input.as_ref() { Some(i) => i.serialize(), @@ -72,7 +78,10 @@ impl Executor for InMemoryExecutor where I: Input { } } -impl InMemoryExecutor where I: Input { +impl InMemoryExecutor +where + I: Input, +{ pub fn new(harness_fn: HarnessFunction) -> Self { unsafe { os_signals::setup_crash_handlers::(); @@ -98,14 +107,17 @@ pub mod unix_signals { use std::{mem, process, ptr}; use crate::executors::inmemory::CURRENT_INMEMORY_EXECUTOR_PTR; - use crate::inputs::Input; use crate::executors::Executor; + use crate::inputs::Input; pub extern "C" fn libaflrs_executor_inmem_handle_crash( _sig: c_int, info: siginfo_t, _void: c_void, - ) where I: Input, E: Executor { + ) where + I: Input, + E: Executor, + { unsafe { if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() { println!( @@ -123,7 +135,10 @@ pub mod unix_signals { _sig: c_int, _info: siginfo_t, _void: c_void, - ) where I: Input, E: Executor { + ) where + I: Input, + E: Executor, + { dbg!("TIMEOUT/SIGUSR2 received"); unsafe { if CURRENT_INMEMORY_EXECUTOR_PTR == ptr::null() { @@ -137,7 +152,11 @@ pub mod unix_signals { process::abort(); } - pub unsafe fn setup_crash_handlers() where I: Input, E: Executor { + pub unsafe fn setup_crash_handlers() + where + I: Input, + E: Executor, + { let mut sa: sigaction = mem::zeroed(); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); sa.sa_flags = SA_NODEFER | SA_SIGINFO; @@ -167,15 +186,14 @@ use unix_signals as os_signals; #[cfg(not(unix))] compile_error!("InMemoryExecutor not yet supported on this OS"); - #[cfg(test)] mod tests { - use std::any::Any; - use crate::executors::{Executor, ExitKind}; use crate::executors::inmemory::InMemoryExecutor; + use crate::executors::{Executor, ExitKind}; use crate::inputs::Input; use crate::observers::Observer; use crate::AflError; + use std::any::Any; #[derive(Clone)] struct NopInput {} diff --git a/src/executors/mod.rs b/src/executors/mod.rs index 7b2c74d921..f82e4694d4 100644 --- a/src/executors/mod.rs +++ b/src/executors/mod.rs @@ -13,7 +13,10 @@ pub enum ExitKind { // TODO unbox input -pub trait Executor where I: Input { +pub trait Executor +where + I: Input, +{ /// Run the target fn run_target(&mut self) -> Result; @@ -37,4 +40,4 @@ pub trait Executor where I: Input { /// Get the linked observers fn observers(&self) -> &Vec>; -} \ No newline at end of file +} diff --git a/src/feedbacks/mod.rs b/src/feedbacks/mod.rs index 48f636fd20..07f36e97dc 100644 --- a/src/feedbacks/mod.rs +++ b/src/feedbacks/mod.rs @@ -1,80 +1,142 @@ extern crate num; use crate::corpus::Testcase; -use crate::inputs::Input; use crate::executors::Executor; +use crate::inputs::Input; use crate::observers::MapObserver; use num::Integer; +use std::cell::RefCell; use std::marker::PhantomData; -pub trait Feedback where I: Input { +pub trait Feedback +where + I: Input, +{ /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) fn is_interesting(&mut self, executor: &dyn Executor, entry: &Testcase) -> u8; } -/* -pub trait Feedback { - /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) - fn is_interesting(&mut self, executor: &dyn Executor, entry: &Testcase) -> u8; -} - -pub trait Reducer { +pub trait Reducer +where + T: Integer + Copy + 'static, +{ fn reduce(first: T, second: T) -> T; } -pub trait MaxReducer { +pub struct MaxReducer +where + T: Integer + Copy + 'static, +{ + phantom: PhantomData, +} + +impl Reducer for MaxReducer +where + T: Integer + Copy + 'static, +{ fn reduce(first: T, second: T) -> T { - if first > second { first } else { second } + if first > second { + first + } else { + second + } } } -pub trait MinReducer { +pub struct MinReducer +where + T: Integer + Copy + 'static, +{ + phantom: PhantomData, +} + +impl Reducer for MinReducer +where + T: Integer + Copy + 'static, +{ fn reduce(first: T, second: T) -> T { - if first < second { first } else { second } + if first < second { + first + } else { + second + } } } -pub struct MapFeedback> { - virgin_map: Vec, - _phantom: PhantomData, +/// The most common AFL-like feedback type +pub struct MapFeedback<'a, T, R> +where + T: Integer + Copy + 'static, + R: Reducer, +{ + /// Contains information about untouched entries + history_map: &'a RefCell>, + /// The observer this feedback struct observes + map_observer: &'a RefCell>, + /// Phantom Data of Reducer + phantom: PhantomData, } -impl<'a, MapT: Integer + Copy + 'static, ReducerT: Reducer> Feedback for MapFeedback { - fn is_interesting(&mut self, executor: &dyn Executor, _entry: &dyn Testcase) -> u8 { +impl<'a, T, R, I> Feedback for MapFeedback<'a, T, R> +where + T: Integer + Copy + 'static, + R: Reducer, + I: Input, +{ + fn is_interesting(&mut self, _executor: &dyn Executor, entry: &Testcase) -> u8 { let mut interesting = 0; - for observer in executor.get_observers() { - if let Some(o) = observer.as_any().downcast_ref::>() { - // TODO: impl. correctly, optimize - for (virgin, map) in self.virgin_map.iter_mut().zip(o.get_map().iter()) { - let reduced = ReducerT::reduce(*virgin, *map); - if *virgin != reduced { - *virgin = reduced; - if interesting < 250 { - interesting += 25 - } - } + + // TODO: impl. correctly, optimize + for (history, map) in self + .history_map + .borrow_mut() + .iter_mut() + .zip(self.map_observer.borrow().get_map().iter()) + { + let reduced = R::reduce(*history, *map); + if *history != reduced { + *history = reduced; + interesting += 25; + if interesting >= 250 { + return 255; } - break } } interesting } } -impl<'a, MapT: Integer + Copy + 'static, ReducerT: Reducer> MapFeedback { - /// Create new MapFeedback using a static map observer - pub fn new(map_size: usize) -> Self { +impl<'a, T, R> MapFeedback<'a, T, R> +where + T: Integer + Copy + 'static, + R: Reducer, +{ + /// Create new MapFeedback using a map observer, and a map. + /// The map can be shared. + pub fn new( + map_observer: &'a RefCell>, + history_map: &'a RefCell>, + ) -> Self { MapFeedback { - virgin_map: vec![MapT::zero(); map_size], - _phantom: PhantomData, + map_observer: map_observer, + history_map: history_map, + phantom: PhantomData, } } } -#[allow(dead_code)] -type MaxMapFeedback = MapFeedback>; -#[allow(dead_code)] -type MinMapFeedback = MapFeedback>; +/// Returns a usable history map of the given size +pub fn create_history_map(map_size: usize) -> RefCell> +where + T: Default + Clone, +{ + { + RefCell::new(vec![T::default(); map_size]) + } +} -*/ \ No newline at end of file +#[allow(dead_code)] +type MaxMapFeedback<'a, T> = MapFeedback<'a, T, MaxReducer>; +#[allow(dead_code)] +type MinMapFeedback<'a, T> = MapFeedback<'a, T, MinReducer>; diff --git a/src/inputs/bytes.rs b/src/inputs/bytes.rs index 98bb1cfdc7..7353697dc2 100644 --- a/src/inputs/bytes.rs +++ b/src/inputs/bytes.rs @@ -33,9 +33,7 @@ impl HasBytesVec for BytesInput { impl BytesInput { pub fn new(bytes: Vec) -> Self { - BytesInput { - bytes: bytes - } + BytesInput { bytes: bytes } } } diff --git a/src/inputs/mod.rs b/src/inputs/mod.rs index 79ec14e0d7..86451437da 100644 --- a/src/inputs/mod.rs +++ b/src/inputs/mod.rs @@ -1,15 +1,15 @@ pub mod bytes; -pub use bytes::{HasBytesVec, BytesInput}; +pub use bytes::{BytesInput, HasBytesVec}; +use std::clone::Clone; use std::fs::File; use std::io::Read; use std::io::Write; use std::path::PathBuf; -use std::clone::Clone; use crate::AflError; -pub trait Input : Clone { +pub trait Input: Clone { fn to_file(&self, path: &PathBuf) -> Result<(), AflError> { let mut file = File::create(path)?; file.write_all(self.serialize()?)?; diff --git a/src/lib.rs b/src/lib.rs index d1dd22f15a..8f9aaeb5a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ pub enum AflError { NotImplemented(String), #[error("Unknown error: {0}")] Unknown(String), - } +} #[cfg(test)] mod tests { diff --git a/src/mutators/mod.rs b/src/mutators/mod.rs index 9385afb6e3..dc54667ad9 100644 --- a/src/mutators/mod.rs +++ b/src/mutators/mod.rs @@ -1,12 +1,15 @@ +use crate::corpus::Corpus; use crate::inputs::Input; use crate::utils::HasRand; -use crate::corpus::Corpus; use crate::AflError; pub mod scheduled; -pub trait HasOptionCorpus where I: Input { - type C : Corpus; +pub trait HasOptionCorpus +where + I: Input, +{ + type C: Corpus; /// Get the associated corpus, if any fn corpus(&self) -> &Option>; @@ -18,7 +21,10 @@ pub trait HasOptionCorpus where I: Input { fn set_corpus(&mut self, corpus: Option>); } -pub trait Mutator : HasRand where I: Input { +pub trait Mutator: HasRand +where + I: Input, +{ /// Mutate a given input fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError>; diff --git a/src/mutators/scheduled.rs b/src/mutators/scheduled.rs index 212f1c78d6..d0f97552fe 100644 --- a/src/mutators/scheduled.rs +++ b/src/mutators/scheduled.rs @@ -1,7 +1,7 @@ -use crate::mutators::{HasOptionCorpus, Mutator}; -use crate::utils::{Rand, HasRand}; use crate::corpus::Corpus; -use crate::inputs::{Input, HasBytesVec}; +use crate::inputs::{HasBytesVec, Input}; +use crate::mutators::{HasOptionCorpus, Mutator}; +use crate::utils::{HasRand, Rand}; use crate::AflError; use std::marker::PhantomData; @@ -9,7 +9,10 @@ use std::marker::PhantomData; /// The generic function type that identifies mutations type MutationFunction = fn(&mut M, &mut I) -> Result<(), AflError>; -pub trait ComposedByMutations where I: Input { +pub trait ComposedByMutations +where + I: Input, +{ /// Get a mutation by index fn mutation_by_idx(&self, index: usize) -> Result, AflError>; @@ -20,7 +23,10 @@ pub trait ComposedByMutations where I: Input { fn add_mutation(&mut self, mutation: MutationFunction); } -pub trait ScheduledMutator: Mutator + HasOptionCorpus + ComposedByMutations where I: Input { +pub trait ScheduledMutator: Mutator + HasOptionCorpus + ComposedByMutations +where + I: Input, +{ /// Compute the number of iterations used to apply stacked mutations fn iterations(&mut self, _input: &I) -> u64 { 1 << (1 + self.rand_mut().below(7)) @@ -50,13 +56,23 @@ pub trait ScheduledMutator: Mutator + HasOptionCorpus + ComposedByMutat } } -pub struct DefaultScheduledMutator<'a, I, R, C> where I: Input, R: Rand, C: Corpus { +pub struct DefaultScheduledMutator<'a, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ rand: &'a mut R, corpus: Option>, - mutations: Vec> + mutations: Vec>, } -impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus { +impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ type R = R; fn rand(&self) -> &Self::R { @@ -67,7 +83,12 @@ impl<'a, I, R, C> HasRand for DefaultScheduledMutator<'_, I, R, C> where I: Inpu } } -impl HasOptionCorpus for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus { +impl HasOptionCorpus for DefaultScheduledMutator<'_, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ type C = C; fn corpus(&self) -> &Option> { @@ -83,13 +104,23 @@ impl HasOptionCorpus for DefaultScheduledMutator<'_, I, R, C> where } } -impl<'a, I, R, C> Mutator for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus { +impl<'a, I, R, C> Mutator for DefaultScheduledMutator<'_, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ fn mutate(&mut self, input: &mut I, _stage_idx: i32) -> Result<(), AflError> { self.scheduled_mutate(input, _stage_idx) } } -impl<'a, I, R, C> ComposedByMutations for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus { +impl<'a, I, R, C> ComposedByMutations for DefaultScheduledMutator<'_, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ fn mutation_by_idx(&self, index: usize) -> Result, AflError> { if index >= self.mutations.len() { return Err(AflError::Unknown("oob".to_string())); @@ -106,44 +137,70 @@ impl<'a, I, R, C> ComposedByMutations for DefaultScheduledMutator<'_, I, R, C } } -impl<'a, I, R, C> ScheduledMutator for DefaultScheduledMutator<'_, I, R, C> where I: Input, R: Rand, C: Corpus { +impl<'a, I, R, C> ScheduledMutator for DefaultScheduledMutator<'_, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ // Just use the default methods } -impl<'a, I, R, C> DefaultScheduledMutator<'a, I, R, C> where I: Input, R: Rand, C: Corpus { +impl<'a, I, R, C> DefaultScheduledMutator<'a, I, R, C> +where + I: Input, + R: Rand, + C: Corpus, +{ /// Create a new DefaultScheduledMutator instance without mutations and corpus pub fn new(rand: &'a mut R) -> Self { DefaultScheduledMutator { rand: rand, corpus: None, - mutations: vec![] + mutations: vec![], } } /// Create a new DefaultScheduledMutator instance specifying mutations and corpus too - pub fn new_all(rand: &'a mut R, corpus: Option>, mutations: Vec>) -> Self { + pub fn new_all( + rand: &'a mut R, + corpus: Option>, + mutations: Vec>, + ) -> Self { DefaultScheduledMutator { rand: rand, corpus: corpus, - mutations: mutations + mutations: mutations, } } } /// Bitflip mutation for inputs with a bytes vector -pub fn mutation_bitflip(mutator: &mut M, input: &mut I) -> Result<(), AflError> where M: Mutator, I: Input + HasBytesVec { +pub fn mutation_bitflip(mutator: &mut M, input: &mut I) -> Result<(), AflError> +where + M: Mutator, + I: Input + HasBytesVec, +{ let bit = mutator.rand_mut().below(input.bytes().len() as u64) as usize; input.bytes_mut()[bit >> 3] ^= (128 >> (bit & 7)) as u8; Ok(()) } /// Schedule some selected byte level mutations given a ScheduledMutator type -pub struct HavocBytesMutator where I: Input + HasBytesVec, S: ScheduledMutator { +pub struct HavocBytesMutator +where + I: Input + HasBytesVec, + S: ScheduledMutator, +{ scheduled: S, - phantom: PhantomData + phantom: PhantomData, } -impl HasRand for HavocBytesMutator where I: Input + HasBytesVec, S: ScheduledMutator { +impl HasRand for HavocBytesMutator +where + I: Input + HasBytesVec, + S: ScheduledMutator, +{ type R = S::R; fn rand(&self) -> &Self::R { @@ -154,7 +211,11 @@ impl HasRand for HavocBytesMutator where I: Input + HasBytesVec, S: } } -impl HasOptionCorpus for HavocBytesMutator where I: Input + HasBytesVec, S: ScheduledMutator { +impl HasOptionCorpus for HavocBytesMutator +where + I: Input + HasBytesVec, + S: ScheduledMutator, +{ type C = S::C; fn corpus(&self) -> &Option> { @@ -170,31 +231,44 @@ impl HasOptionCorpus for HavocBytesMutator where I: Input + HasBy } } -impl Mutator for HavocBytesMutator where I: Input + HasBytesVec, S: ScheduledMutator { +impl Mutator for HavocBytesMutator +where + I: Input + HasBytesVec, + S: ScheduledMutator, +{ fn mutate(&mut self, input: &mut I, stage_idx: i32) -> Result<(), AflError> { self.scheduled.mutate(input, stage_idx) } } -impl HavocBytesMutator where I: Input + HasBytesVec, S: ScheduledMutator { +impl HavocBytesMutator +where + I: Input + HasBytesVec, + S: ScheduledMutator, +{ /// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap pub fn new(mut scheduled: S) -> Self { scheduled.add_mutation(mutation_bitflip); HavocBytesMutator { scheduled: scheduled, - phantom: PhantomData + phantom: PhantomData, } } } -impl<'a, I, R, C> HavocBytesMutator> where I: Input + HasBytesVec, R: Rand, C: Corpus { +impl<'a, I, R, C> HavocBytesMutator> +where + I: Input + HasBytesVec, + R: Rand, + C: Corpus, +{ /// Create a new HavocBytesMutator instance wrapping DefaultScheduledMutator pub fn new_default(rand: &'a mut R) -> Self { let mut scheduled = DefaultScheduledMutator::<'a, I, R, C>::new(rand); scheduled.add_mutation(mutation_bitflip); HavocBytesMutator { scheduled: scheduled, - phantom: PhantomData + phantom: PhantomData, } } -} \ No newline at end of file +} diff --git a/src/observers/mod.rs b/src/observers/mod.rs index d5d6a7c3d5..752744ff24 100644 --- a/src/observers/mod.rs +++ b/src/observers/mod.rs @@ -1,14 +1,14 @@ extern crate num; -use std::slice::from_raw_parts_mut; -use std::any::Any; use num::Integer; +use std::any::Any; +use std::slice::from_raw_parts_mut; 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 { fn flush(&mut self) -> Result<(), AflError> { Ok(()) } diff --git a/src/stages/mod.rs b/src/stages/mod.rs index 55a1ade03d..b589e05871 100644 --- a/src/stages/mod.rs +++ b/src/stages/mod.rs @@ -1,22 +1,28 @@ pub mod mutational; use crate::corpus::Testcase; -use crate::inputs::Input; use crate::engines::Engine; +use crate::inputs::Input; use crate::AflError; use std::cell::RefCell; use std::rc::Rc; -pub trait HasEngine<'a, I> where I: Input { - type E : Engine<'a, I>; +pub trait HasEngine<'a, I> +where + I: Input, +{ + type E: Engine<'a, I>; fn engine(&self) -> &Self::E; fn engine_mut(&mut self) -> &mut Self::E; } -pub trait Stage<'a, I> : HasEngine<'a, I> where I: Input { +pub trait Stage<'a, I>: HasEngine<'a, I> +where + I: Input, +{ /// Run the stage fn perform(&mut self, entry: Rc>>) -> Result<(), AflError>; } diff --git a/src/stages/mutational.rs b/src/stages/mutational.rs index 713c45ff85..ec36c60133 100644 --- a/src/stages/mutational.rs +++ b/src/stages/mutational.rs @@ -1,17 +1,20 @@ -use crate::AflError; -use crate::mutators::Mutator; -use crate::inputs::Input; -use crate::utils::{Rand, HasRand}; -use crate::stages::{Stage, HasEngine}; use crate::corpus::testcase::Testcase; use crate::engines::Engine; +use crate::inputs::Input; +use crate::mutators::Mutator; +use crate::stages::{HasEngine, Stage}; +use crate::utils::{HasRand, Rand}; +use crate::AflError; use std::cell::RefCell; use std::rc::Rc; // TODO create HasMutatorsVec trait -pub trait MutationalStage<'a, I> : Stage<'a, I> + HasRand where I: Input { +pub trait MutationalStage<'a, I>: Stage<'a, I> + HasRand +where + I: Input, +{ fn mutators(&self) -> &Vec>>; fn mutators_mut(&mut self) -> &mut Vec>>; @@ -41,18 +44,27 @@ pub trait MutationalStage<'a, I> : Stage<'a, I> + HasRand where I: Input { input = entry.borrow_mut().load_input()?.clone(); } - Ok(()) } } -pub struct DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +pub struct DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ rand: &'a mut R, engine: &'a mut E, - mutators: Vec>> + mutators: Vec>>, } -impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ type R = R; fn rand(&self) -> &Self::R { @@ -63,7 +75,12 @@ impl<'a, I, R, E> HasRand for DefaultMutationalStage<'a, I, R, E> where I: Input } } -impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ type E = E; fn engine(&self) -> &Self::E { @@ -75,7 +92,12 @@ impl<'a, I, R, E> HasEngine<'a, I> for DefaultMutationalStage<'a, I, R, E> where } } -impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ fn mutators(&self) -> &Vec>> { &self.mutators } @@ -85,18 +107,28 @@ impl<'a, I, R, E> MutationalStage<'a, I> for DefaultMutationalStage<'a, I, R, E> } } -impl<'a, I, R, E> Stage<'a, I> for DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +impl<'a, I, R, E> Stage<'a, I> for DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ fn perform(&mut self, entry: Rc>>) -> Result<(), AflError> { self.perform_mutational(entry) } } -impl<'a, I, R, E> DefaultMutationalStage<'a, I, R, E> where I: Input, R: Rand, E: Engine<'a, I> { +impl<'a, I, R, E> DefaultMutationalStage<'a, I, R, E> +where + I: Input, + R: Rand, + E: Engine<'a, I>, +{ pub fn new(rand: &'a mut R, engine: &'a mut E) -> Self { DefaultMutationalStage { rand: rand, engine: engine, - mutators: vec![] + mutators: vec![], } } -} \ No newline at end of file +} diff --git a/src/utils.rs b/src/utils.rs index ee32d74e57..2c9da6763a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -41,7 +41,7 @@ pub trait Rand: Debug { /// Has a Rand box field pub trait HasRand { - type R : Rand; + type R: Rand; /// Get the hold Rand instance fn rand(&self) -> &Self::R;