From 60b0b16a6029194fd94292273638135ac5a8d486 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 11 Dec 2020 15:34:56 +0100 Subject: [PATCH 1/3] 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 { From 55c043ec73bd658bd8eb3d147ea9dfc54b5258bf Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 11 Dec 2020 17:08:50 +0100 Subject: [PATCH 2/3] doh --- afl/src/engines/mod.rs | 50 ++++++++------- afl/src/events/mod.rs | 117 ++++++++++++++++++++--------------- afl/src/feedbacks/mod.rs | 8 +-- afl/src/observers/mod.rs | 24 ++++--- afl/src/stages/mod.rs | 86 ++++++++++++++++++++++++- afl/src/stages/mutational.rs | 48 +++++++------- 6 files changed, 223 insertions(+), 110 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index 2ad0cca4ae..23717cb7c3 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -194,7 +194,7 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - EM: EventManager, + EM: EventManager, { let mut added = 0; for _ in 0..num { @@ -234,7 +234,7 @@ where I: Input, { executor: E, - phantom: PhantomData, + phantom: PhantomData<(OT, I)>, } impl Engine @@ -263,24 +263,25 @@ where } } -pub trait Fuzzer +pub trait Fuzzer where - EM: EventManager, + EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, 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, @@ -288,8 +289,6 @@ where engine: &mut Engine, manager: &mut EM, ) -> Result - where - FT: FeedbacksTuple { let (_, idx) = corpus.next(rand)?; @@ -301,15 +300,15 @@ where Ok(idx) } - fn fuzz_loop( + fn fuzz_loop( &mut self, rand: &mut R, state: &mut State, corpus: &mut C, engine: &mut Engine, manager: &mut EM, - ) -> Result<(), AflError> where - FT: FeedbacksTuple{ + ) -> Result<(), AflError> + { let mut last = current_milliseconds(); loop { self.fuzz_one(rand, state, corpus, engine, manager)?; @@ -325,41 +324,44 @@ where } } -pub struct StdFuzzer +pub struct StdFuzzer where - EM: EventManager, + EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, { - stages: Vec>>, + stages: Vec>>, } -impl Fuzzer for StdFuzzer +impl Fuzzer for StdFuzzer where - EM: EventManager, + EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, 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, + EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, @@ -403,8 +405,8 @@ mod tests { let testcase = Testcase::new(vec![0; 4]).into(); corpus.add(testcase); - let executor = InMemoryExecutor::::new(harness, tuple_list!()); - let mut state = State::new(); + let executor = InMemoryExecutor::new(harness, tuple_list!()); + let mut state = State::::new(); let mut events_manager = LoggerEventManager::new(stderr()); let mut engine = Engine::new(executor); diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index 3c1752023a..ac1c5ccc5a 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -16,11 +16,13 @@ use std::io::Write; use crate::engines::State; use crate::executors::Executor; +use crate::observers::ObserversTuple; +use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; -use crate::serde_anymap::{Ptr, PtrMut}; +use crate::serde_anymap::{SerdeAny, Ptr, PtrMut}; use crate::utils::Rand; use crate::AflError; -use crate::{corpus::Corpus, serde_anymap::SerdeAny}; +use crate::corpus::Corpus; /// Indicate if an event worked or not pub enum BrokerEventResult { @@ -33,7 +35,7 @@ pub enum BrokerEventResult { pub trait ShowStats {} /// A custom event, for own messages, with own handler. -pub trait CustomEvent: SerdeAny + Serialize +pub trait CustomEvent: SerdeAny + Serialize where I: Input, { @@ -48,9 +50,10 @@ where /// Events sent around in the library #[derive(Serialize, Deserialize)] #[serde(bound = "I: serde::de::DeserializeOwned")] -pub enum Event<'a, I> +pub enum Event<'a, I, OT> where I: Input, + OT: ObserversTuple { LoadInitial { sender_id: u64, @@ -59,7 +62,7 @@ where NewTestcase { sender_id: u64, input: Ptr<'a, I>, - observers: PtrMut<'a, crate::observers::observer_serde::NamedSerdeAnyMap>, + observers: PtrMut<'a, OT>, corpus_count: usize, }, UpdateStats { @@ -90,14 +93,15 @@ where Custom { sender_id: u64, // TODO: Allow custom events - // custom_event: Box>, + // custom_event: Box>, }, } -impl<'a, I> Event<'a, I> +impl<'a, I, OT> Event<'a, I, OT> where I: Input, - //CE: CustomEvent, + OT: ObserversTuple + //CE: CustomEvent, { pub fn name(&self) -> &str { match self { @@ -159,29 +163,31 @@ where } } -pub trait EventManager +pub trait EventManager where C: Corpus, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, I: Input, R: Rand, { /// Fire an Event - fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError>; + fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError>; /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process(&mut self, state: &mut State, corpus: &mut C) -> Result; + fn process(&mut self, state: &mut State, corpus: &mut C) -> Result; #[inline] - fn on_recv(&self, _state: &mut State, _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(()) } // TODO the broker has a state? do we need to pass state and corpus? - fn handle_in_broker(&mut self, event: &Event) -> Result { + fn handle_in_broker(&mut self, event: &Event) -> Result { match event { Event::LoadInitial { sender_id: _, @@ -238,8 +244,8 @@ where fn handle_in_client( &mut self, - event: Event, - _state: &mut State, + event: Event, + _state: &mut State, _corpus: &mut C, ) -> Result<(), AflError> { match event { @@ -263,7 +269,7 @@ where } /*TODO - fn on_recv(&self, state: &mut State, _corpus: &mut C) -> Result<(), AflError> { + fn on_recv(&self, state: &mut State, _corpus: &mut C) -> Result<(), AflError> { println!( "#{}\t exec/s: {}", state.executions(), @@ -275,10 +281,16 @@ where */ #[cfg(feature = "std")] -pub struct LoggerEventManager +pub struct LoggerEventManager where + C: Corpus, + E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, + I: Input, + R: Rand, W: Write, - //CE: CustomEvent, + //CE: CustomEvent, { writer: W, count: usize, @@ -288,21 +300,23 @@ where execs_over_sec: u64, corpus_count: usize, - phantom: PhantomData<(C, E, I, R)>, + phantom: PhantomData<(C, E, OT, FT, I, R)>, } #[cfg(feature = "std")] -impl EventManager for LoggerEventManager +impl EventManager for LoggerEventManager where C: Corpus, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, I: Input, R: Rand, W: Write, - //CE: CustomEvent, + //CE: CustomEvent, { #[inline] - fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError> { + fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError> { match self.handle_in_broker(&event)? { BrokerEventResult::Forward => (), //self.handle_in_client(event, state, corpus)?, // Ignore broker-only events @@ -311,13 +325,13 @@ where Ok(()) } - fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { + fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { let c = self.count; self.count = 0; Ok(c) } - fn handle_in_broker(&mut self, event: &Event) -> Result { + fn handle_in_broker(&mut self, event: &Event) -> Result { match event { Event::NewTestcase { sender_id: _, @@ -377,11 +391,13 @@ where } #[cfg(feature = "std")] -impl LoggerEventManager +impl LoggerEventManager where C: Corpus, I: Input, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, R: Rand, W: Write, //TODO CE: CustomEvent, @@ -400,16 +416,18 @@ where /// Eventmanager for multi-processed application #[cfg(feature = "std")] -pub struct LlmpBrokerEventManager +pub struct LlmpBrokerEventManager where C: Corpus, I: Input, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, R: Rand, - //CE: CustomEvent, + //CE: CustomEvent, { llmp_broker: llmp::LlmpBroker, - phantom: PhantomData<(C, E, I, R)>, + phantom: PhantomData<(C, E, OT, FT, I, R)>, } #[cfg(feature = "std")] @@ -424,35 +442,39 @@ const _LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741; /// Eventmanager for multi-processed application #[cfg(feature = "std")] -pub struct LlmpClientEventManager +pub struct LlmpClientEventManager where C: Corpus, I: Input, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, R: Rand, - //CE: CustomEvent, + //CE: CustomEvent, { _llmp_client: llmp::LlmpClient, - phantom: PhantomData<(C, E, I, R)>, + phantom: PhantomData<(C, E, OT, FT, I, R)>, } #[cfg(feature = "std")] -impl EventManager for LlmpBrokerEventManager +impl EventManager for LlmpBrokerEventManager where C: Corpus, E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, I: Input, R: Rand, { /// Fire an Event - fn fire<'a>(&mut self, event: Event<'a, I>) -> Result<(), AflError> { + fn fire<'a>(&mut self, event: Event<'a, I, OT>) -> Result<(), AflError> { let serialized = postcard::to_allocvec(&event)?; self.llmp_broker .send_buf(LLMP_TAG_EVENT_TO_CLIENT, &serialized)?; Ok(()) } - fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { + fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { // TODO: iterators /* let mut handled = vec![]; @@ -481,13 +503,13 @@ where Ok(0) } - fn on_recv(&self, _state: &mut State, _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(()) } - fn handle_in_broker(&mut self, event: &Event) -> Result { + fn handle_in_broker(&mut self, event: &Event) -> Result { match event { Event::LoadInitial { sender_id: _, @@ -542,8 +564,8 @@ where fn handle_in_client( &mut self, - event: Event, - /*client: &dyn EventManager,*/ _state: &mut State, + event: Event, + _state: &mut State, _corpus: &mut C, ) -> Result<(), AflError> { match event { @@ -572,17 +594,17 @@ mod tests { use crate::events::Event; use crate::inputs::bytes::BytesInput; - use crate::observers::observer_serde::NamedSerdeAnyMap; - use crate::observers::{Observer, StdMapObserver}; + use crate::observers::{Observer, StdMapObserver, ObserversTuple}; + use crate::tuples::{MatchNameAndType, Named, tuple_list, tuple_list_type}; use crate::serde_anymap::{Ptr, PtrMut}; static mut MAP: [u32; 4] = [0; 4]; #[test] fn test_event_serde() { - let mut map = NamedSerdeAnyMap::new(); + let obv = StdMapObserver::new("test", unsafe { &mut MAP }); - map.insert(Box::new(obv), &"key".to_string()); + let mut map = tuple_list!(obv); let i = BytesInput::new(vec![0]); let e = Event::NewTestcase { @@ -594,19 +616,16 @@ mod tests { let j = serde_json::to_string(&e).unwrap(); - let d: Event = serde_json::from_str(&j).unwrap(); + let d: Event)> = serde_json::from_str(&j).unwrap(); match d { Event::NewTestcase { sender_id: _, input: _, - observers: obs, + observers, corpus_count: _, } => { - let o = obs - .as_ref() - .get::>(&"key".to_string()) - .unwrap(); - assert_eq!("test".to_string(), *o.name()); + let o = observers.as_ref().match_name_type::>("test").unwrap(); + assert_eq!("test", o.name()); } _ => panic!("mistmatch".to_string()), }; diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index 5783469891..9897d71459 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -19,7 +19,7 @@ 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: Named +pub trait Feedback: Named + 'static where I: Input, { @@ -39,7 +39,7 @@ where } } -pub trait FeedbacksTuple: TupleList + MatchType + MatchNameAndType +pub trait FeedbacksTuple: MatchType + MatchNameAndType where I: Input { @@ -61,7 +61,7 @@ I: Input{ impl FeedbacksTuple for (Head, Tail) where Head: Feedback, - Tail: FeedbacksTuple, + Tail: FeedbacksTuple + TupleList, I: Input { fn is_interesting_all(&mut self, input: &I, observers: &OT) -> Result { @@ -90,7 +90,7 @@ impl FeedbacksTuple for (Head, Tail) where } /// A Reducer function is used to aggregate values for the novelty search -pub trait Reducer +pub trait Reducer: 'static where T: Integer + Copy + 'static, { diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 73d77d231c..b9326fb8a4 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -1,8 +1,5 @@ extern crate num; -use alloc::boxed::Box; -use alloc::string::String; -use core::any::Any; use serde::{Deserialize, Serialize}; use crate::serde_anymap::ArrayMut; @@ -26,21 +23,23 @@ pub trait Observer: Named + 'static { } } -pub trait ObserversTuple: TupleList + MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned { +pub trait ObserversTuple: 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)); + //fn for_each(&self, f: fn(&dyn Observer)); + //fn for_each_mut(&mut self, f: fn(&mut 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)) { } + //fn for_each(&self, f: fn(&dyn Observer)) { } + //fn for_each_mut(&mut self, f: fn(&mut dyn Observer)) { } } impl ObserversTuple for (Head, Tail) where - Head: Observer, - Tail: ObserversTuple, + Head: Observer + serde::Serialize + serde::de::DeserializeOwned, + Tail: ObserversTuple + TupleList, { fn reset_all(&mut self) -> Result<(), AflError> { self.0.reset()?; @@ -52,10 +51,15 @@ impl ObserversTuple for (Head, Tail) where self.1.post_exec_all() } - fn for_each(&self, f: fn(&dyn Observer)) { - f(self.0); + /*fn for_each(&self, f: fn(&dyn Observer)) { + f(&self.0); self.1.for_each(f) } + + fn for_each_mut(&mut self, f: fn(&mut dyn Observer)) { + f(&mut self.0); + self.1.for_each_mut(f) + }*/ } /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information diff --git a/afl/src/stages/mod.rs b/afl/src/stages/mod.rs index a1b9829ba3..efe81d5e2d 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -7,15 +7,16 @@ use crate::events::EventManager; use crate::executors::{HasObservers, Executor}; use crate::observers::ObserversTuple; use crate::feedbacks::FeedbacksTuple; +use crate::tuples::{TupleList, MatchType}; 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, + EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, FT: FeedbacksTuple, @@ -34,3 +35,84 @@ where corpus_idx: usize, ) -> Result<(), AflError>; } + +pub trait StagesTuple +where + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + fn perform_all( + &mut self, + rand: &mut R, + state: &mut State, + corpus: &mut C, + engine: &mut Engine, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), AflError>; + fn for_each(&self, f: fn(&dyn Stage)); + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)); +} + +impl StagesTuple for () +where + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + fn perform_all( + &mut self, + rand: &mut R, + state: &mut State, + corpus: &mut C, + engine: &mut Engine, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), AflError> { Ok(()) } + fn for_each(&self, f: fn(&dyn Stage)) { } + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { } +} + +impl StagesTuple for (Head, Tail) where + Head: Stage, + Tail: StagesTuple + TupleList, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + FT: FeedbacksTuple, + C: Corpus, + I: Input, + R: Rand, +{ + fn perform_all( + &mut self, + rand: &mut R, + state: &mut State, + corpus: &mut C, + engine: &mut Engine, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), AflError> { + self.0.perform(rand, state, corpus, engine, manager, corpus_idx)?; + self.1.perform_all(rand, state, corpus, engine, manager, corpus_idx) + } + + fn for_each(&self, f: fn(&dyn Stage)) { + f(&self.0); + self.1.for_each(f) + } + + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { + f(&mut self.0); + self.1.for_each_mut(f) + } +} \ No newline at end of file diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 7f3ea6f203..2f80e59aea 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -1,8 +1,9 @@ use core::marker::PhantomData; 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::mutators::Mutator; use crate::stages::Corpus; @@ -18,12 +19,13 @@ 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, + EM: EventManager, + E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, @@ -45,9 +47,9 @@ where fn perform_mutational( &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> { @@ -84,26 +86,28 @@ where } /// The default mutational stage -pub struct StdMutationalStage +pub struct StdMutationalStage where M: Mutator, - EM: EventManager, - E: Executor, + EM: EventManager, + E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, { mutator: M, - phantom: PhantomData<(EM, E, OT, C, I, R)>, + phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, } -impl MutationalStage for StdMutationalStage +impl MutationalStage for StdMutationalStage where M: Mutator, - EM: EventManager, - E: Executor, + EM: EventManager, + E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, @@ -121,12 +125,13 @@ where } } -impl Stage for StdMutationalStage +impl Stage for StdMutationalStage where M: Mutator, - EM: EventManager, - E: Executor, + EM: EventManager, + E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, @@ -135,9 +140,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> { @@ -145,12 +150,13 @@ where } } -impl StdMutationalStage +impl StdMutationalStage where M: Mutator, - EM: EventManager, - E: Executor, + EM: EventManager, + E: Executor + HasObservers, OT: ObserversTuple, + FT: FeedbacksTuple, C: Corpus, I: Input, R: Rand, From 4f6a27ff14782dbb55ab0f03d1ab66a405194ef1 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 11 Dec 2020 17:55:43 +0100 Subject: [PATCH 3/3] works --- afl/src/engines/mod.rs | 78 ++++++++++++++++------------------ afl/src/events/mod.rs | 42 +++++++++++------- afl/src/executors/inmemory.rs | 20 +++++---- afl/src/executors/mod.rs | 7 ++- afl/src/feedbacks/mod.rs | 70 ++++++++++++++++++++---------- afl/src/observers/mod.rs | 38 ++++++++++------- afl/src/stages/mod.rs | 25 ++++++----- afl/src/stages/mutational.rs | 10 +++-- afl/src/tuples.rs | 80 +++++++++++++++++++++++------------ fuzzers/libfuzzer/src/lib.rs | 23 +++++----- 10 files changed, 234 insertions(+), 159 deletions(-) diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index 23717cb7c3..d74811fe97 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -1,19 +1,18 @@ //! The engine is the core piece of every good fuzzer use alloc::boxed::Box; -use alloc::vec::Vec; use core::fmt::Debug; use core::marker::PhantomData; use hashbrown::HashMap; use crate::corpus::{Corpus, Testcase}; use crate::events::{Event, EventManager}; -use crate::executors::{HasObservers, Executor}; -use crate::feedbacks::{FeedbacksTuple}; -use crate::observers::ObserversTuple; +use crate::executors::{Executor, HasObservers}; +use crate::feedbacks::FeedbacksTuple; use crate::generators::Generator; use crate::inputs::Input; -use crate::stages::Stage; +use crate::observers::ObserversTuple; +use crate::stages::StagesTuple; use crate::utils::{current_milliseconds, Rand}; use crate::AflError; @@ -27,7 +26,7 @@ pub struct State where I: Input, R: Rand, - FT: FeedbacksTuple + FT: FeedbacksTuple, { /// How many times the executor ran the harness/target executions: usize, @@ -37,14 +36,14 @@ where metadatas: HashMap<&'static str, Box>, // additional_corpuses: HashMap<&'static str, Box>, feedbacks: FT, - phantom: PhantomData, + phantom: PhantomData<(I, R)>, } impl State where I: Input, R: Rand, - FT: FeedbacksTuple + FT: FeedbacksTuple, { /// Get executions #[inline] @@ -117,7 +116,7 @@ where pub fn evaluate_input(&mut self, input: &I, executor: &mut E) -> Result where E: Executor + HasObservers, - OT: ObserversTuple + OT: ObserversTuple, { executor.reset_observers()?; executor.run_target(&input)?; @@ -216,12 +215,12 @@ where Ok(()) } - pub fn new() -> Self { + pub fn new(feedbacks: FT) -> Self { Self { executions: 0, start_time: current_milliseconds(), metadatas: HashMap::default(), - feedbacks: vec![], + feedbacks: feedbacks, phantom: PhantomData, } } @@ -263,8 +262,9 @@ where } } -pub trait Fuzzer +pub trait Fuzzer where + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, @@ -273,13 +273,9 @@ where I: Input, R: Rand, { - fn stages(&self) -> &[Box>]; + fn stages(&self) -> &ST; - fn stages_mut(&mut self) -> &mut Vec>>; - - fn add_stage(&mut self, stage: Box>) { - self.stages_mut().push(stage); - } + fn stages_mut(&mut self) -> &mut ST; fn fuzz_one( &mut self, @@ -288,13 +284,11 @@ where corpus: &mut C, engine: &mut Engine, manager: &mut EM, - ) -> Result - { + ) -> Result { let (_, idx) = corpus.next(rand)?; - for stage in self.stages_mut() { - stage.perform(rand, state, corpus, engine, manager, idx)?; - } + self.stages_mut() + .perform_all(rand, state, corpus, engine, manager, idx)?; manager.process(state, corpus)?; Ok(idx) @@ -307,8 +301,7 @@ where corpus: &mut C, engine: &mut Engine, manager: &mut EM, - ) -> Result<(), AflError> - { + ) -> Result<(), AflError> { let mut last = current_milliseconds(); loop { self.fuzz_one(rand, state, corpus, engine, manager)?; @@ -324,8 +317,9 @@ where } } -pub struct StdFuzzer +pub struct StdFuzzer where + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, @@ -334,11 +328,14 @@ where I: Input, R: Rand, { - stages: Vec>>, + stages: ST, + phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, } -impl Fuzzer for StdFuzzer +impl Fuzzer + for StdFuzzer where + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, @@ -347,17 +344,18 @@ where I: Input, R: Rand, { - fn stages(&self) -> &[Box>] { + fn stages(&self) -> &ST { &self.stages } - fn stages_mut(&mut self) -> &mut Vec>> { + fn stages_mut(&mut self) -> &mut ST { &mut self.stages } } -impl StdFuzzer +impl StdFuzzer where + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, @@ -366,8 +364,11 @@ where I: Input, R: Rand, { - pub fn new() -> Self { - Self { stages: vec![] } + pub fn new(stages: ST) -> Self { + Self { + stages: stages, + phantom: PhantomData, + } } } @@ -376,8 +377,6 @@ where #[cfg(test)] mod tests { - use alloc::boxed::Box; - #[cfg(feature = "std")] use std::io::stderr; @@ -405,18 +404,15 @@ mod tests { let testcase = Testcase::new(vec![0; 4]).into(); corpus.add(testcase); - let executor = InMemoryExecutor::new(harness, tuple_list!()); - let mut state = State::::new(); + let executor = InMemoryExecutor::::new(harness, tuple_list!()); + let mut state = State::new(tuple_list!()); let mut events_manager = LoggerEventManager::new(stderr()); let mut engine = Engine::new(executor); let mut mutator = StdScheduledMutator::new(); mutator.add_mutation(mutation_bitflip); let stage = StdMutationalStage::new(mutator); - let mut fuzzer = StdFuzzer::new(); - fuzzer.add_stage(Box::new(stage)); - - // + let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); for i in 0..1000 { fuzzer diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index ac1c5ccc5a..a65b6a5347 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -14,15 +14,15 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use std::io::Write; +use crate::corpus::Corpus; use crate::engines::State; use crate::executors::Executor; -use crate::observers::ObserversTuple; use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; -use crate::serde_anymap::{SerdeAny, Ptr, PtrMut}; +use crate::observers::ObserversTuple; +use crate::serde_anymap::{Ptr, PtrMut, SerdeAny}; use crate::utils::Rand; use crate::AflError; -use crate::corpus::Corpus; /// Indicate if an event worked or not pub enum BrokerEventResult { @@ -53,7 +53,7 @@ where pub enum Event<'a, I, OT> where I: Input, - OT: ObserversTuple + OT: ObserversTuple, { LoadInitial { sender_id: u64, @@ -100,8 +100,7 @@ where impl<'a, I, OT> Event<'a, I, OT> where I: Input, - OT: ObserversTuple - //CE: CustomEvent, + OT: ObserversTuple, //CE: CustomEvent, { pub fn name(&self) -> &str { match self { @@ -304,7 +303,8 @@ where } #[cfg(feature = "std")] -impl EventManager for LoggerEventManager +impl EventManager + for LoggerEventManager where C: Corpus, E: Executor, @@ -325,7 +325,11 @@ where Ok(()) } - fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { + fn process( + &mut self, + _state: &mut State, + _corpus: &mut C, + ) -> Result { let c = self.count; self.count = 0; Ok(c) @@ -457,7 +461,8 @@ where } #[cfg(feature = "std")] -impl EventManager for LlmpBrokerEventManager +impl EventManager + for LlmpBrokerEventManager where C: Corpus, E: Executor, @@ -474,7 +479,11 @@ where Ok(()) } - fn process(&mut self, _state: &mut State, _corpus: &mut C) -> Result { + fn process( + &mut self, + _state: &mut State, + _corpus: &mut C, + ) -> Result { // TODO: iterators /* let mut handled = vec![]; @@ -594,15 +603,14 @@ mod tests { use crate::events::Event; use crate::inputs::bytes::BytesInput; - use crate::observers::{Observer, StdMapObserver, ObserversTuple}; - use crate::tuples::{MatchNameAndType, Named, tuple_list, tuple_list_type}; + use crate::observers::{Observer, ObserversTuple, StdMapObserver}; use crate::serde_anymap::{Ptr, PtrMut}; + use crate::tuples::{tuple_list, tuple_list_type, MatchNameAndType, Named}; static mut MAP: [u32; 4] = [0; 4]; #[test] fn test_event_serde() { - let obv = StdMapObserver::new("test", unsafe { &mut MAP }); let mut map = tuple_list!(obv); @@ -616,7 +624,8 @@ mod tests { let j = serde_json::to_string(&e).unwrap(); - let d: Event)> = serde_json::from_str(&j).unwrap(); + let d: Event)> = + serde_json::from_str(&j).unwrap(); match d { Event::NewTestcase { sender_id: _, @@ -624,7 +633,10 @@ mod tests { observers, corpus_count: _, } => { - let o = observers.as_ref().match_name_type::>("test").unwrap(); + let o = observers + .as_ref() + .match_name_type::>("test") + .unwrap(); assert_eq!("test", o.name()); } _ => panic!("mistmatch".to_string()), diff --git a/afl/src/executors/inmemory.rs b/afl/src/executors/inmemory.rs index 93f617a0b0..eb9989b5dd 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, HasObservers, ExitKind}; +use crate::executors::{Executor, ExitKind, HasObservers}; use crate::inputs::{HasTargetBytes, Input}; -use crate::observers::{ObserversTuple}; +use crate::observers::ObserversTuple; use crate::AflError; /// The (unsafe) pointer to the current inmem executor, for the current run. @@ -17,7 +17,7 @@ type HarnessFunction = fn(&dyn Executor, &[u8]) -> ExitKind; pub struct InMemoryExecutor where I: Input + HasTargetBytes, - OT: ObserversTuple + OT: ObserversTuple, { harness: HarnessFunction, observers: OT, @@ -26,7 +26,7 @@ where impl Executor for InMemoryExecutor where I: Input + HasTargetBytes, - OT: ObserversTuple + OT: ObserversTuple, { #[inline] fn run_target(&mut self, input: &I) -> Result { @@ -42,9 +42,11 @@ where } } -impl HasObservers for InMemoryExecutor where -I: Input + HasTargetBytes, -OT: ObserversTuple { +impl HasObservers for InMemoryExecutor +where + I: Input + HasTargetBytes, + OT: ObserversTuple, +{ #[inline] fn observers(&self) -> &OT { &self.observers @@ -59,7 +61,7 @@ OT: ObserversTuple { impl InMemoryExecutor where I: Input + HasTargetBytes, - OT: ObserversTuple + OT: ObserversTuple, { pub fn new(harness_fn: HarnessFunction, observers: OT) -> Self { #[cfg(feature = "std")] @@ -190,7 +192,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 } diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index 2f0a28d890..ea209b8dd0 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::observers::{ObserversTuple}; +use crate::observers::ObserversTuple; use crate::AflError; /// How an execution finished. @@ -12,7 +12,10 @@ pub enum ExitKind { Timeout, } -pub trait HasObservers where OT: ObserversTuple { +pub trait HasObservers +where + OT: ObserversTuple, +{ /// Get the linked observers fn observers(&self) -> &OT; diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index 9897d71459..4356e53b03 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -4,10 +4,10 @@ use alloc::vec::Vec; use core::marker::PhantomData; use num::Integer; -use crate::inputs::Input; -use crate::observers::{ObserversTuple, Observer, MapObserver}; use crate::corpus::Testcase; -use crate::tuples::{Named, TupleList, MatchNameAndType, MatchType}; +use crate::inputs::Input; +use crate::observers::{MapObserver, Observer, ObserversTuple}; +use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList}; use crate::AflError; pub type MaxMapFeedback = MapFeedback, O>; @@ -24,7 +24,11 @@ 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: &OT) -> 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] @@ -41,41 +45,63 @@ where pub trait FeedbacksTuple: MatchType + MatchNameAndType where - I: Input + I: Input, { - fn is_interesting_all(&mut self, input: &I, observers: &OT) -> Result; + 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(())} +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 +impl FeedbacksTuple for (Head, Tail) +where Head: Feedback, Tail: FeedbacksTuple + TupleList, - I: Input + 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 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>{ + fn append_metadata_all(&mut self, testcase: &mut Testcase) -> Result<(), AflError> { self.0.append_metadata(testcase)?; - self.1.append_metadata_all(testcase) + self.1.append_metadata_all(testcase) } - fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError>{ + fn discard_metadata_all(&mut self, input: &I) -> Result<(), AflError> { self.0.discard_metadata(input)?; - self.1.discard_metadata_all(input) + self.1.discard_metadata_all(input) } /*fn for_each(&self, f: fn(&dyn Feedback)) { @@ -191,7 +217,7 @@ where O: MapObserver + 'static, { #[inline] - fn name(&self) -> &'static str { + fn name(&self) -> &str { self.name } } @@ -211,13 +237,13 @@ where } } - pub fn new_with_observer(map_observer: &O) -> Self { + /*pub fn new_with_observer(map_observer: &O) -> Self { Self { history_map: vec![T::default(); map_observer.map().len()], name: map_observer.name(), phantom: PhantomData, } - } + }*/ } impl MapFeedback diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index b9326fb8a4..a6be37e922 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -3,12 +3,12 @@ extern crate num; use serde::{Deserialize, Serialize}; use crate::serde_anymap::ArrayMut; -use crate::tuples::{TupleList, MatchNameAndType, MatchType, Named}; +use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList}; use crate::AflError; /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: Named + 'static { +pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static { /// The testcase finished execution, calculate any changes. #[inline] fn flush(&mut self) -> Result<(), AflError> { @@ -23,7 +23,9 @@ pub trait Observer: Named + 'static { } } -pub trait ObserversTuple: MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned { +pub trait ObserversTuple: + 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)); @@ -31,24 +33,29 @@ pub trait ObserversTuple: MatchNameAndType + MatchType + serde::Serialize + serd } impl ObserversTuple for () { - fn reset_all(&mut self) -> Result<(), AflError> { Ok(()) } - fn post_exec_all(&mut self) -> Result<(), AflError> { Ok(()) } + 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)) { } //fn for_each_mut(&mut self, f: fn(&mut dyn Observer)) { } } -impl ObserversTuple for (Head, Tail) where - Head: Observer + serde::Serialize + serde::de::DeserializeOwned, +impl ObserversTuple for (Head, Tail) +where + Head: Observer, Tail: ObserversTuple + TupleList, { fn reset_all(&mut self) -> Result<(), AflError> { self.0.reset()?; - self.1.reset_all() + self.1.reset_all() } fn post_exec_all(&mut self) -> Result<(), AflError> { self.0.post_exec()?; - self.1.post_exec_all() + self.1.post_exec_all() } /*fn for_each(&self, f: fn(&dyn Observer)) { @@ -105,7 +112,7 @@ where { map: ArrayMut, initial: T, - name: &'static str, + name: String, } impl Observer for StdMapObserver @@ -118,12 +125,13 @@ where } } -impl Named 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 name(&self) -> &'static str { - self.name + fn name(&self) -> &str { + self.name.as_str() } } @@ -202,4 +210,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 efe81d5e2d..f63dc2b855 100644 --- a/afl/src/stages/mod.rs +++ b/afl/src/stages/mod.rs @@ -4,11 +4,11 @@ pub use mutational::StdMutationalStage; use crate::corpus::Corpus; use crate::engines::{Engine, State}; use crate::events::EventManager; -use crate::executors::{HasObservers, Executor}; -use crate::observers::ObserversTuple; +use crate::executors::{Executor, HasObservers}; use crate::feedbacks::FeedbacksTuple; -use crate::tuples::{TupleList, MatchType}; use crate::inputs::Input; +use crate::observers::ObserversTuple; +use crate::tuples::{MatchType, TupleList}; use crate::utils::Rand; use crate::AflError; @@ -77,12 +77,15 @@ where engine: &mut Engine, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), AflError> { Ok(()) } - fn for_each(&self, f: fn(&dyn Stage)) { } - fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { } + ) -> Result<(), AflError> { + Ok(()) + } + fn for_each(&self, f: fn(&dyn Stage)) {} + fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) {} } -impl StagesTuple for (Head, Tail) where +impl StagesTuple for (Head, Tail) +where Head: Stage, Tail: StagesTuple + TupleList, EM: EventManager, @@ -102,8 +105,10 @@ impl StagesTuple for manager: &mut EM, corpus_idx: usize, ) -> Result<(), AflError> { - self.0.perform(rand, state, corpus, engine, manager, corpus_idx)?; - self.1.perform_all(rand, state, corpus, engine, manager, corpus_idx) + self.0 + .perform(rand, state, corpus, engine, manager, corpus_idx)?; + self.1 + .perform_all(rand, state, corpus, engine, manager, corpus_idx) } fn for_each(&self, f: fn(&dyn Stage)) { @@ -115,4 +120,4 @@ impl StagesTuple for f(&mut self.0); self.1.for_each_mut(f) } -} \ No newline at end of file +} diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 2f80e59aea..804326e020 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -1,11 +1,11 @@ use core::marker::PhantomData; use crate::events::EventManager; -use crate::executors::{HasObservers, Executor}; -use crate::observers::ObserversTuple; +use crate::executors::{Executor, HasObservers}; use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; use crate::mutators::Mutator; +use crate::observers::ObserversTuple; use crate::stages::Corpus; use crate::stages::{Engine, Stage}; use crate::utils::Rand; @@ -101,7 +101,8 @@ where phantom: PhantomData<(EM, E, OT, FT, C, I, R)>, } -impl MutationalStage for StdMutationalStage +impl MutationalStage + for StdMutationalStage where M: Mutator, EM: EventManager, @@ -125,7 +126,8 @@ where } } -impl Stage for StdMutationalStage +impl Stage + for StdMutationalStage where M: Mutator, EM: EventManager, diff --git a/afl/src/tuples.rs b/afl/src/tuples.rs index daf00d98dd..d7209b8bab 100644 --- a/afl/src/tuples.rs +++ b/afl/src/tuples.rs @@ -1,6 +1,6 @@ -pub use tuple_list::TupleList; pub use tuple_list::tuple_list; pub use tuple_list::tuple_list_type; +pub use tuple_list::TupleList; use core::any::TypeId; @@ -9,10 +9,13 @@ pub trait HasLen { } impl HasLen for () { - fn len(&self) -> usize { 0 } + fn len(&self) -> usize { + 0 + } } - -impl HasLen for (Head, Tail) where + +impl HasLen for (Head, Tail) +where Tail: TupleList + HasLen, { fn len(&self) -> usize { @@ -26,11 +29,16 @@ pub trait MatchFirstType { } impl MatchFirstType for () { - fn match_first_type(&self) -> Option<&T> { None } - fn match_first_type_mut(&mut self) -> Option<&mut T> { None } + 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 + +impl MatchFirstType for (Head, Tail) +where Head: 'static, Tail: TupleList + MatchFirstType, { @@ -57,11 +65,16 @@ pub trait MatchType { } impl MatchType for () { - fn match_type(&self, f: fn(t: &T)) { () } - fn match_type_mut(&mut self, f: fn(t: &mut T)) { () } + 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 + +impl MatchType for (Head, Tail) +where Head: 'static, Tail: TupleList + MatchType, { @@ -81,7 +94,7 @@ impl MatchType for (Head, Tail) where } pub trait Named { - fn name(&self) -> &'static str; + fn name(&self) -> &str; } pub trait MatchNameAndType { @@ -90,11 +103,16 @@ pub trait MatchNameAndType { } 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 } + 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 + +impl MatchNameAndType for (Head, Tail) +where Head: 'static + Named, Tail: TupleList + MatchNameAndType, { @@ -122,35 +140,41 @@ pub trait Prepend: TupleList { } /// Implement prepend for tuple list. -impl Prepend for Tail where Tail: TupleList { +impl Prepend for Tail +where + Tail: TupleList, +{ type PreprendResult = Self; fn prepend(self, value: T) -> (T, Self::PreprendResult) { (value, self) } } - + pub trait Append: TupleList { type AppendResult: TupleList; - + fn append(self, value: T) -> Self::AppendResult; } - + /// Implement append for an empty tuple list. impl Append for () { type AppendResult = (T, ()); - - fn append(self, value: T) -> Self::AppendResult { (value, ()) } + + fn append(self, value: T) -> Self::AppendResult { + (value, ()) + } } - + /// Implement append for non-empty tuple list. -impl Append for (Head, Tail) where +impl Append for (Head, Tail) +where Self: TupleList, Tail: Append, (Head, Tail::AppendResult): TupleList, { type AppendResult = (Head, Tail::AppendResult); - + fn append(self, value: T) -> Self::AppendResult { let (head, tail) = self; return (head, tail.append(value)); @@ -165,13 +189,13 @@ trait PlusOne { } impl PlusOne for i32 { fn plus_one(&mut self) { *self += 1; } } impl PlusOne for String { fn plus_one(&mut self) { self.push('1'); } } - + // Now we have to implement trait for an empty tuple, // thus defining initial condition. impl PlusOne for () { fn plus_one(&mut self) {} } - + // Now we can implement trait for a non-empty tuple list, // thus defining recursion and supporting tuple lists of arbitrary length. impl PlusOne for (Head, Tail) where diff --git a/fuzzers/libfuzzer/src/lib.rs b/fuzzers/libfuzzer/src/lib.rs index c4e17e4923..70c020a273 100644 --- a/fuzzers/libfuzzer/src/lib.rs +++ b/fuzzers/libfuzzer/src/lib.rs @@ -22,8 +22,9 @@ use afl::mutators::HasMaxSize; use afl::observers::StdMapObserver; use afl::stages::mutational::StdMutationalStage; use afl::utils::StdRand; +use afl::tuples::tuple_list; -// const MAP_SIZE: usize = 65536; +const MAP_SIZE: usize = 65536; #[no_mangle] extern "C" { @@ -59,18 +60,12 @@ pub extern "C" fn afl_libfuzzer_main() { StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { __lafl_max_edges_size as usize }); - let edges_feedback = MaxMapFeedback::new_with_observer(&edges_observer); - - let mut executor = InMemoryExecutor::new(harness); - let mut state = State::new(); - executor.add_observer(Box::new(edges_observer)); - state.add_feedback(Box::new(edges_feedback)); + let edges_feedback = MaxMapFeedback::>::new(&NAME_COV_MAP, MAP_SIZE); + let executor = InMemoryExecutor::new(harness, tuple_list!(edges_observer)); + let mut state = State::new(tuple_list!(edges_feedback)); + let mut engine = Engine::new(executor); - let mut mutator = HavocBytesMutator::new_default(); - mutator.set_max_size(4096); - - let stage = StdMutationalStage::new(mutator); state .generate_initial_inputs( @@ -83,9 +78,11 @@ pub extern "C" fn afl_libfuzzer_main() { ) .expect("Failed to load initial inputs"); - let mut fuzzer = StdFuzzer::new(); + let mut mutator = HavocBytesMutator::new_default(); + mutator.set_max_size(4096); - fuzzer.add_stage(Box::new(stage)); + let stage = StdMutationalStage::new(mutator); + let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); fuzzer .fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut events)