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