From 60b0b16a6029194fd94292273638135ac5a8d486 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 11 Dec 2020 15:34:56 +0100 Subject: [PATCH] start working on tuples --- afl/Cargo.toml | 1 + afl/src/engines/mod.rs | 117 +++++++++++++++++----------------- afl/src/executors/inmemory.rs | 34 ++++++---- afl/src/executors/mod.rs | 52 ++++++--------- afl/src/feedbacks/mod.rs | 84 +++++++++++++++++++----- afl/src/lib.rs | 1 + afl/src/observers/mod.rs | 66 +++++++++++-------- afl/src/stages/mod.rs | 14 ++-- afl/src/stages/mutational.rs | 28 ++++---- afl/src/tuples.rs | 37 ++++++++++- 10 files changed, 273 insertions(+), 161 deletions(-) diff --git a/afl/Cargo.toml b/afl/Cargo.toml index 99c42680f7..d0b023a8e8 100644 --- a/afl/Cargo.toml +++ b/afl/Cargo.toml @@ -31,6 +31,7 @@ default = ["std"] std = [] [dependencies] +tuple_list = "0.1.2" hashbrown = { version = "0.9", features = ["serde"] } # A faster hashmap, nostd compatible libc = "0.2" # For (*nix) libc num = "*" diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index f5a31360c3..2ad0cca4ae 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -8,8 +8,9 @@ use hashbrown::HashMap; use crate::corpus::{Corpus, Testcase}; use crate::events::{Event, EventManager}; -use crate::executors::Executor; -use crate::feedbacks::Feedback; +use crate::executors::{HasObservers, Executor}; +use crate::feedbacks::{FeedbacksTuple}; +use crate::observers::ObserversTuple; use crate::generators::Generator; use crate::inputs::Input; use crate::stages::Stage; @@ -22,10 +23,11 @@ pub trait StateMetadata: Debug { } /// The state a fuzz run. -pub struct State +pub struct State where I: Input, R: Rand, + FT: FeedbacksTuple { /// How many times the executor ran the harness/target executions: usize, @@ -34,14 +36,15 @@ where /// Metadata stored for this state by one of the components metadatas: HashMap<&'static str, Box>, // additional_corpuses: HashMap<&'static str, Box>, - feedbacks: Vec>>, + feedbacks: FT, phantom: PhantomData, } -impl State +impl State where I: Input, R: Rand, + FT: FeedbacksTuple { /// Get executions #[inline] @@ -98,39 +101,31 @@ where /// Returns vector of feebacks #[inline] - pub fn feedbacks(&self) -> &[Box>] { + pub fn feedbacks(&self) -> &FT { &self.feedbacks } /// Returns vector of feebacks (mutable) #[inline] - pub fn feedbacks_mut(&mut self) -> &mut Vec>> { + pub fn feedbacks_mut(&mut self) -> &mut FT { &mut self.feedbacks } - /// Adds a feedback - #[inline] - pub fn add_feedback(&mut self, feedback: Box>) { - self.feedbacks_mut().push(feedback); - } - - // TODO move some of these, like evaluate_input, to FuzzingEngine + // TODO move some of these, like evaluate_input, to Engine /// Runs the input and triggers observers and feedback - pub fn evaluate_input(&mut self, input: &I, executor: &mut E) -> Result + pub fn evaluate_input(&mut self, input: &I, executor: &mut E) -> Result where - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple { executor.reset_observers()?; executor.run_target(&input)?; self.set_executions(self.executions() + 1); executor.post_exec_observers()?; - let mut fitness = 0; let observers = executor.observers(); - for feedback in self.feedbacks_mut() { - fitness += feedback.is_interesting(&input, observers)?; - } + let fitness = self.feedbacks_mut().is_interesting_all(&input, observers)?; Ok(fitness) } @@ -138,10 +133,7 @@ where #[inline] 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(()) + self.feedbacks_mut().discard_metadata_all(&input) } /// Creates a new testcase, appending the metadata from each feedback @@ -149,10 +141,7 @@ where 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)?; - } - + self.feedbacks_mut().append_metadata_all(&mut testcase)?; Ok(testcase) } @@ -191,19 +180,20 @@ where } } - pub fn generate_initial_inputs( + pub fn generate_initial_inputs( &mut self, rand: &mut R, corpus: &mut C, generator: &mut G, - engine: &mut Engine, + engine: &mut Engine, manager: &mut EM, num: usize, ) -> Result<(), AflError> where G: Generator, C: Corpus, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, EM: EventManager, { let mut added = 0; @@ -237,18 +227,20 @@ where } } -pub struct Engine +pub struct Engine where - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, I: Input, { executor: E, phantom: PhantomData, } -impl Engine +impl Engine where - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, I: Input, { /// Return the executor @@ -271,30 +263,34 @@ where } } -pub trait Fuzzer +pub trait Fuzzer where EM: EventManager, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, 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 fuzz_one( + fn fuzz_one( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &mut C, - engine: &mut Engine, + engine: &mut Engine, manager: &mut EM, - ) -> Result { + ) -> Result + where + FT: FeedbacksTuple + { let (_, idx) = corpus.next(rand)?; for stage in self.stages_mut() { @@ -305,14 +301,15 @@ where Ok(idx) } - fn fuzz_loop( + fn fuzz_loop( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &mut C, - engine: &mut Engine, + engine: &mut Engine, manager: &mut EM, - ) -> Result<(), AflError> { + ) -> Result<(), AflError> where + FT: FeedbacksTuple{ let mut last = current_milliseconds(); loop { self.fuzz_one(rand, state, corpus, engine, manager)?; @@ -328,38 +325,41 @@ where } } -pub struct StdFuzzer +pub struct StdFuzzer where EM: EventManager, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, { - stages: Vec>>, + stages: Vec>>, } -impl Fuzzer for StdFuzzer +impl Fuzzer for StdFuzzer where EM: EventManager, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, 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 StdFuzzer +impl StdFuzzer where EM: EventManager, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, @@ -388,6 +388,7 @@ mod tests { use crate::inputs::bytes::BytesInput; use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator}; use crate::stages::mutational::StdMutationalStage; + use crate::tuples::tuple_list; use crate::utils::StdRand; fn harness(_executor: &dyn Executor, _buf: &[u8]) -> ExitKind { @@ -402,7 +403,7 @@ mod tests { let testcase = Testcase::new(vec![0; 4]).into(); corpus.add(testcase); - let executor = InMemoryExecutor::::new(harness); + let executor = InMemoryExecutor::::new(harness, tuple_list!()); let mut state = State::new(); let mut events_manager = LoggerEventManager::new(stderr()); diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index 8ce1e4b0c6..93f617a0b0 100644 --- a/afl/src/executors/inmemory.rs +++ b/afl/src/executors/inmemory.rs @@ -1,9 +1,9 @@ use core::ffi::c_void; use core::ptr; -use crate::executors::{Executor, ExitKind}; +use crate::executors::{Executor, HasObservers, ExitKind}; use crate::inputs::{HasTargetBytes, Input}; -use crate::observers::observer_serde::NamedSerdeAnyMap; +use crate::observers::{ObserversTuple}; use crate::AflError; /// The (unsafe) pointer to the current inmem executor, for the current run. @@ -14,23 +14,25 @@ static mut CURRENT_INMEMORY_EXECUTOR_PTR: *const c_void = ptr::null(); type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; /// The inmem executor simply calls a target function, then returns afterwards. -pub struct InMemoryExecutor +pub struct InMemoryExecutor where I: Input + HasTargetBytes, + OT: ObserversTuple { harness: HarnessFunction, - observers: NamedSerdeAnyMap, + observers: OT, } -impl Executor for InMemoryExecutor +impl Executor for InMemoryExecutor where I: Input + HasTargetBytes, + OT: ObserversTuple { #[inline] fn run_target(&mut self, input: &I) -> Result { let bytes = input.target_bytes(); unsafe { - CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor as *const c_void; + CURRENT_INMEMORY_EXECUTOR_PTR = self as *const InMemoryExecutor as *const c_void; } let ret = (self.harness)(self, bytes.as_slice()); unsafe { @@ -38,30 +40,35 @@ where } Ok(ret) } +} +impl HasObservers for InMemoryExecutor where +I: Input + HasTargetBytes, +OT: ObserversTuple { #[inline] - fn observers(&self) -> &NamedSerdeAnyMap { + fn observers(&self) -> &OT { &self.observers } #[inline] - fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap { + fn observers_mut(&mut self) -> &mut OT { &mut self.observers } } -impl InMemoryExecutor +impl InMemoryExecutor where I: Input + HasTargetBytes, + OT: ObserversTuple { - pub fn new(harness_fn: HarnessFunction) -> Self { + pub fn new(harness_fn: HarnessFunction, observers: OT) -> Self { #[cfg(feature = "std")] unsafe { os_signals::setup_crash_handlers::(); } Self { harness: harness_fn, - observers: NamedSerdeAnyMap::new(), + observers: observers, } } } @@ -169,6 +176,7 @@ mod tests { use crate::executors::inmemory::InMemoryExecutor; use crate::executors::{Executor, ExitKind}; use crate::inputs::{HasTargetBytes, Input, TargetBytes}; + use crate::tuples::{tuple_list, tuple_list_type}; use serde::{Deserialize, Serialize}; @@ -182,7 +190,7 @@ mod tests { } #[cfg(feature = "std")] - fn test_harness_fn_nop(_executor: &dyn Executor, buf: &[u8]) -> ExitKind { + fn test_harness_fn_nop(_executor: &dyn Executor, buf: &[u8]) -> ExitKind { println!("Fake exec with buf of len {}", buf.len()); ExitKind::Ok } @@ -194,7 +202,7 @@ mod tests { #[test] fn test_inmem_exec() { - let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop); + let mut in_mem_executor = InMemoryExecutor::new(test_harness_fn_nop, tuple_list!()); let mut input = NopInput {}; assert!(in_mem_executor.run_target(&mut input).is_ok()); } diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index 73f8c6e8fd..2f0a28d890 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -1,10 +1,7 @@ pub mod inmemory; -use alloc::boxed::Box; - use crate::inputs::Input; -use crate::observers::observer_serde::NamedSerdeAnyMap; -use crate::observers::Observer; +use crate::observers::{ObserversTuple}; use crate::AflError; /// How an execution finished. @@ -15,6 +12,26 @@ pub enum ExitKind { Timeout, } +pub trait HasObservers where OT: ObserversTuple { + /// Get the linked observers + fn observers(&self) -> &OT; + + /// Get the linked observers + fn observers_mut(&mut self) -> &mut OT; + + /// Reset the state of all the observes linked to this executor + #[inline] + fn reset_observers(&mut self) -> Result<(), AflError> { + self.observers_mut().reset_all() + } + + /// Run the post exec hook for all the observes linked to this executor + #[inline] + fn post_exec_observers(&mut self) -> Result<(), AflError> { + self.observers_mut().post_exec_all() + } +} + /// An executor takes the given inputs, and runs the harness/target. pub trait Executor where @@ -22,31 +39,4 @@ where { /// Instruct the target about the input and run fn run_target(&mut self, input: &I) -> Result; - - /// Get the linked observers - fn observers(&self) -> &NamedSerdeAnyMap; - - /// Get the linked observers - fn observers_mut(&mut self) -> &mut NamedSerdeAnyMap; - - /// Add a linked observer - fn add_observer(&mut self, observer: Box) { - let name = observer.name().clone(); - self.observers_mut().insert(observer, &name); - } - - /// Reset the state of all the observes linked to this executor - #[inline] - fn reset_observers(&mut self) -> Result<(), AflError> { - self.observers_mut().for_each_mut(|_, x| Ok(x.reset()?))?; - Ok(()) - } - - /// Run the post exec hook for all the observes linked to this executor - #[inline] - fn post_exec_observers(&mut self) -> Result<(), AflError> { - 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 988e54f5be..5783469891 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -5,10 +5,10 @@ use core::marker::PhantomData; use num::Integer; use crate::inputs::Input; -use crate::observers::observer_serde::NamedSerdeAnyMap; -use crate::observers::MapObserver; +use crate::observers::{ObserversTuple, Observer, MapObserver}; +use crate::corpus::Testcase; +use crate::tuples::{Named, TupleList, MatchNameAndType, MatchType}; use crate::AflError; -use crate::{corpus::Testcase, observers::Observer}; pub type MaxMapFeedback = MapFeedback, O>; pub type MinMapFeedback = MapFeedback, O>; @@ -19,12 +19,12 @@ pub type MinMapFeedback = 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. -pub trait Feedback +pub trait Feedback: Named where I: Input, { /// is_interesting should return the "Interestingness" from 0 to 255 (percent times 2.55) - fn is_interesting(&mut self, input: &I, observers: &NamedSerdeAnyMap) -> Result; + fn is_interesting(&mut self, input: &I, observers: &OT) -> Result; /// Append to the testcase the generated metadata in case of a new corpus item #[inline] @@ -37,9 +37,56 @@ where fn discard_metadata(&mut self, _input: &I) -> Result<(), AflError> { Ok(()) } +} - /// The name of this feedback - fn name(&self) -> &String; +pub trait FeedbacksTuple: TupleList + MatchType + MatchNameAndType +where + I: Input +{ + fn is_interesting_all(&mut self, input: &I, observers: &OT) -> Result; + fn append_metadata_all(&mut self, testcase: &mut Testcase) -> Result<(), AflError>; + fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>; + //fn for_each(&self, f: fn(&dyn Feedback)); + //fn for_each_mut(&mut self, f: fn(&mut dyn Feedback)); +} + +impl FeedbacksTuple for () where +I: Input{ + fn is_interesting_all(&mut self, input: &I, observers: &OT) -> Result { Ok(0) } + fn append_metadata_all(&mut self, testcase: &mut Testcase) -> Result<(), AflError> { Ok(())} + fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError> { Ok(())} + //fn for_each(&self, f: fn(&dyn Feedback)) {} + //fn for_each_mut(&mut self, f: fn(&mut dyn Feedback)) {} +} + +impl FeedbacksTuple for (Head, Tail) where + Head: Feedback, + Tail: FeedbacksTuple, + I: Input +{ + fn is_interesting_all(&mut self, input: &I, observers: &OT) -> Result { + Ok(self.0.is_interesting(input, observers)? + self.1.is_interesting_all(input, observers)?) + } + + fn append_metadata_all(&mut self, testcase: &mut Testcase) -> Result<(), AflError>{ + self.0.append_metadata(testcase)?; + self.1.append_metadata_all(testcase) + } + + fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>{ + self.0.discard_metadata(input)?; + self.1.discard_metadata_all(input) + } + + /*fn for_each(&self, f: fn(&dyn Feedback)) { + f(&self.0); + self.1.for_each(f) + } + + fn for_each_mut(&mut self, f: fn(&mut dyn Feedback)) { + f(self.0); + self.1.for_each_mut(f) + }*/ } /// A Reducer function is used to aggregate values for the novelty search @@ -102,7 +149,7 @@ where /// Contains information about untouched entries history_map: Vec, /// Name identifier of this instance - name: String, + name: &'static str, /// Phantom Data of Reducer phantom: PhantomData<(R, O)>, } @@ -114,14 +161,14 @@ where O: MapObserver + 'static, I: Input, { - fn is_interesting( + fn is_interesting( &mut self, _input: &I, - observers: &NamedSerdeAnyMap, + observers: &OT, ) -> Result { let mut interesting = 0; // TODO optimize - let observer = observers.get::(&self.name).unwrap(); + let observer = observers.match_name_type::(&self.name).unwrap(); let size = observer.map().len(); for i in 0..size { let history = self.history_map[i]; @@ -135,10 +182,17 @@ where Ok(interesting) } +} +impl Named for MapFeedback +where + T: Integer + Default + Copy + 'static, + R: Reducer, + O: MapObserver + 'static, +{ #[inline] - fn name(&self) -> &String { - &self.name + fn name(&self) -> &'static str { + self.name } } @@ -152,7 +206,7 @@ where pub fn new(name: &'static str, map_size: usize) -> Self { Self { history_map: vec![T::default(); map_size], - name: name.to_string(), + name: name, phantom: PhantomData, } } @@ -160,7 +214,7 @@ where pub fn new_with_observer(map_observer: &O) -> Self { Self { history_map: vec![T::default(); map_observer.map().len()], - name: map_observer.name().to_string(), + name: map_observer.name(), phantom: PhantomData, } } diff --git a/afl/src/lib.rs b/afl/src/lib.rs index 4af4633494..0571ff0bde 100644 --- a/afl/src/lib.rs +++ b/afl/src/lib.rs @@ -19,6 +19,7 @@ pub mod mutators; pub mod observers; pub mod serde_anymap; pub mod stages; +pub mod tuples; pub mod utils; use alloc::string::String; diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 0901350791..73d77d231c 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -5,14 +5,13 @@ use alloc::string::String; use core::any::Any; use serde::{Deserialize, Serialize}; -use crate::serde_anymap::{ArrayMut, SerdeAny}; +use crate::serde_anymap::ArrayMut; +use crate::tuples::{TupleList, MatchNameAndType, MatchType, Named}; use crate::AflError; -// TODO register each observer in the Registry in new() - /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: SerdeAny + 'static { +pub trait Observer: Named + 'static { /// The testcase finished execution, calculate any changes. #[inline] fn flush(&mut self) -> Result<(), AflError> { @@ -25,11 +24,39 @@ pub trait Observer: SerdeAny + 'static { fn post_exec(&mut self) -> Result<(), AflError> { Ok(()) } - - fn name(&self) -> &String; } -crate::create_serde_registry_for_trait!(observer_serde, crate::observers::Observer); +pub trait ObserversTuple: TupleList + MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned { + fn reset_all(&mut self) -> Result<(), AflError>; + fn post_exec_all(&mut self) -> Result<(), AflError>; + fn for_each(&self, f: fn(&dyn Observer)); +} + +impl ObserversTuple for () { + fn reset_all(&mut self) -> Result<(), AflError> { Ok(()) } + fn post_exec_all(&mut self) -> Result<(), AflError> { Ok(()) } + fn for_each(&self, f: fn(&dyn Observer)) { } +} + +impl ObserversTuple for (Head, Tail) where + Head: Observer, + Tail: ObserversTuple, +{ + fn reset_all(&mut self) -> Result<(), AflError> { + self.0.reset()?; + self.1.reset_all() + } + + fn post_exec_all(&mut self) -> Result<(), AflError> { + self.0.post_exec()?; + self.1.post_exec_all() + } + + fn for_each(&self, f: fn(&dyn Observer)) { + f(self.0); + self.1.for_each(f) + } +} /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information pub trait MapObserver @@ -74,7 +101,7 @@ where { map: ArrayMut, initial: T, - name: String, + name: &'static str, } impl Observer for StdMapObserver @@ -85,25 +112,14 @@ where fn reset(&mut self) -> Result<(), AflError> { self.reset_map() } - - #[inline] - fn name(&self) -> &String { - &self.name - } } -impl SerdeAny for StdMapObserver -where - T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +impl Named for StdMapObserver where +T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { #[inline] - fn as_any(&self) -> &dyn Any { - self - } - - #[inline] - fn as_any_mut(&mut self) -> &mut dyn Any { - self + fn name(&self) -> &'static str { + self.name } } @@ -143,7 +159,6 @@ where { /// Creates a new MapObserver pub fn new(name: &'static str, map: &'static mut [T]) -> Self { - observer_serde::RegistryBuilder::register::(); let initial = if map.len() > 0 { map[0] } else { T::default() }; Self { map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())), @@ -154,7 +169,6 @@ where /// Creates a new MapObserver from a raw pointer pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self { - observer_serde::RegistryBuilder::register::(); unsafe { let initial = if len > 0 { *map_ptr } else { T::default() }; StdMapObserver { @@ -166,6 +180,7 @@ where } } +/* #[cfg(feature = "std")] #[cfg(test)] mod tests { @@ -183,3 +198,4 @@ mod tests { assert_eq!(d.name(), o.name()); } } +*/ \ No newline at end of file diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index 202d539056..a1b9829ba3 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -4,17 +4,21 @@ pub use mutational::StdMutationalStage; use crate::corpus::Corpus; use crate::engines::{Engine, State}; use crate::events::EventManager; -use crate::executors::Executor; +use crate::executors::{HasObservers, Executor}; +use crate::observers::ObserversTuple; +use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; use crate::utils::Rand; use crate::AflError; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. -pub trait Stage +pub trait Stage where EM: EventManager, - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, @@ -23,9 +27,9 @@ where fn perform( &mut self, rand: &mut R, - state: &mut State, + state: &mut State, corpus: &mut C, - engine: &mut Engine, + engine: &mut Engine, manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError>; diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index a7d79a9051..7f3ea6f203 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -2,6 +2,7 @@ use core::marker::PhantomData; use crate::events::EventManager; use crate::executors::Executor; +use crate::observers::ObserversTuple; use crate::inputs::Input; use crate::mutators::Mutator; use crate::stages::Corpus; @@ -17,11 +18,12 @@ use crate::serde_anymap::{Ptr, PtrMut}; /// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// Mutational stages will usually have a range of mutations that are /// being applied to the input one by one, between executions. -pub trait MutationalStage: Stage +pub trait MutationalStage: Stage where M: Mutator, EM: EventManager, - E: Executor, + E: Executor, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, @@ -82,24 +84,26 @@ where } /// The default mutational stage -pub struct StdMutationalStage +pub struct StdMutationalStage where M: Mutator, EM: EventManager, - E: Executor, + E: Executor, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, { mutator: M, - phantom: PhantomData<(EM, E, C, I, R)>, + phantom: PhantomData<(EM, E, OT, C, I, R)>, } -impl MutationalStage for StdMutationalStage +impl MutationalStage for StdMutationalStage where M: Mutator, EM: EventManager, - E: Executor, + E: Executor, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, @@ -117,11 +121,12 @@ where } } -impl Stage for StdMutationalStage +impl Stage for StdMutationalStage where M: Mutator, EM: EventManager, - E: Executor, + E: Executor, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, @@ -140,11 +145,12 @@ where } } -impl StdMutationalStage +impl StdMutationalStage where M: Mutator, EM: EventManager, - E: Executor, + E: Executor, + OT: ObserversTuple, C: Corpus, I: Input, R: Rand, diff --git a/afl/src/tuples.rs b/afl/src/tuples.rs index 2972a9723e..daf00d98dd 100644 --- a/afl/src/tuples.rs +++ b/afl/src/tuples.rs @@ -1,6 +1,8 @@ -use tuple_list::TupleList; -use tuple_list::tuple_list; -use core::any::{TypeId, Any}; +pub use tuple_list::TupleList; +pub use tuple_list::tuple_list; +pub use tuple_list::tuple_list_type; + +use core::any::TypeId; pub trait HasLen { fn len(&self) -> usize; @@ -20,10 +22,12 @@ impl HasLen for (Head, Tail) where pub trait MatchFirstType { fn match_first_type(&self) -> Option<&T>; + fn match_first_type_mut(&mut self) -> Option<&mut T>; } impl MatchFirstType for () { fn match_first_type(&self) -> Option<&T> { None } + fn match_first_type_mut(&mut self) -> Option<&mut T> { None } } impl MatchFirstType for (Head, Tail) where @@ -37,14 +41,24 @@ impl MatchFirstType for (Head, Tail) where self.1.match_first_type::() } } + + fn match_first_type_mut(&mut self) -> Option<&mut T> { + if TypeId::of::() == TypeId::of::() { + unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() } + } else { + self.1.match_first_type_mut::() + } + } } pub trait MatchType { fn match_type(&self, f: fn(t: &T)); + fn match_type_mut(&mut self, f: fn(t: &mut T)); } impl MatchType for () { fn match_type(&self, f: fn(t: &T)) { () } + fn match_type_mut(&mut self, f: fn(t: &mut T)) { () } } impl MatchType for (Head, Tail) where @@ -57,6 +71,13 @@ impl MatchType for (Head, Tail) where } self.1.match_type::(f); } + + fn match_type_mut(&mut self, f: fn(t: &mut T)) { + if TypeId::of::() == TypeId::of::() { + f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap()); + } + self.1.match_type_mut::(f); + } } pub trait Named { @@ -65,10 +86,12 @@ pub trait Named { pub trait MatchNameAndType { fn match_name_type(&self, name: &'static str) -> Option<&T>; + fn match_name_type_mut(&mut self, name: &'static str) -> Option<&mut T>; } impl MatchNameAndType for () { fn match_name_type(&self, name: &'static str) -> Option<&T> { None } + fn match_name_type_mut(&mut self, name: &'static str) -> Option<&mut T> { None } } impl MatchNameAndType for (Head, Tail) where @@ -82,6 +105,14 @@ impl MatchNameAndType for (Head, Tail) where self.1.match_name_type::(name) } } + + fn match_name_type_mut(&mut self, name: &'static str) -> Option<&mut T> { + if TypeId::of::() == TypeId::of::() && name == self.0.name() { + unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() } + } else { + self.1.match_name_type_mut::(name) + } + } } pub trait Prepend: TupleList {