diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index e0a8406874..2bebe91ebc 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -220,7 +220,7 @@ where E: Executor + HasObservers, OT: ObserversTuple, { - executor.reset_observers()?; + executor.pre_exec_observers()?; executor.run_target(&input)?; self.set_executions(self.executions() + 1); executor.post_exec_observers()?; diff --git a/afl/src/executors/mod.rs b/afl/src/executors/mod.rs index 0d1ead666f..8c33e2cbaa 100644 --- a/afl/src/executors/mod.rs +++ b/afl/src/executors/mod.rs @@ -31,8 +31,8 @@ where /// Reset the state of all the observes linked to this executor #[inline] - fn reset_observers(&mut self) -> Result<(), AflError> { - self.observers_mut().reset_all() + fn pre_exec_observers(&mut self) -> Result<(), AflError> { + self.observers_mut().pre_exec_all() } /// Run the post exec hook for all the observes linked to this executor diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index 50ce8ff4dd..1718604fa0 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -309,6 +309,8 @@ where } } +// TODO: TimeFeedback + /* #[derive(Serialize, Deserialize)] pub struct MapNoveltiesMetadata { diff --git a/afl/src/mutators/mutations.rs b/afl/src/mutators/mutations.rs index 5d641d4d33..e487b7955c 100644 --- a/afl/src/mutators/mutations.rs +++ b/afl/src/mutators/mutations.rs @@ -6,35 +6,6 @@ use crate::{ AflError, }; -/// The result of a mutation. -/// If the mutation got skipped, the target -/// will not be executed with the returned input. -pub enum MutationResult { - Mutated, - Skipped, -} - -// TODO maybe the mutator arg is not needed -/// The generic function type that identifies mutations -pub type MutationFunction = - fn(&mut M, &mut R, &C, &mut I) -> Result; - -pub trait ComposedByMutations -where - C: Corpus, - I: Input, - R: Rand, -{ - /// Get a mutation by index - fn mutation_by_idx(&self, index: usize) -> MutationFunction; - - /// Get the number of mutations - fn mutations_count(&self) -> usize; - - /// Add a mutation - fn add_mutation(&mut self, mutation: MutationFunction); -} - const ARITH_MAX: u64 = 35; const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; @@ -71,6 +42,36 @@ const INTERESTING_32: [i32; 27] = [ 2147483647, ]; +/// The result of a mutation. +/// If the mutation got skipped, the target +/// will not be executed with the returned input. +#[derive(Clone, Copy, Debug)] +pub enum MutationResult { + Mutated, + Skipped, +} + +// TODO maybe the mutator arg is not needed +/// The generic function type that identifies mutations +pub type MutationFunction = + fn(&mut M, &mut R, &C, &mut I) -> Result; + +pub trait ComposedByMutations +where + C: Corpus, + I: Input, + R: Rand, +{ + /// Get a mutation by index + fn mutation_by_idx(&self, index: usize) -> MutationFunction; + + /// Get the number of mutations + fn mutations_count(&self) -> usize; + + /// Add a mutation + fn add_mutation(&mut self, mutation: MutationFunction); +} + #[inline] fn self_mem_move(data: &mut [u8], from: usize, to: usize, len: usize) { debug_assert!(from + len <= data.len()); diff --git a/afl/src/mutators/scheduled.rs b/afl/src/mutators/scheduled.rs index 18cf7a31be..81c797bd95 100644 --- a/afl/src/mutators/scheduled.rs +++ b/afl/src/mutators/scheduled.rs @@ -1,5 +1,6 @@ use alloc::vec::Vec; -use core::marker::PhantomData; +use core::{fmt, marker::PhantomData}; +use fmt::Debug; use crate::{ inputs::{HasBytesVec, Input}, @@ -56,6 +57,23 @@ where max_size: usize, } +impl Debug for StdScheduledMutator +where + C: Corpus, + I: Input, + R: Rand, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "StdScheduledMutator with {} Mutations, max_size: {}, for Input type {}", + self.mutations.len(), + self.max_size, + core::any::type_name::() + ) + } +} + impl Mutator for StdScheduledMutator where C: Corpus, diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index 6ea5f09ef2..717b937fc7 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -4,11 +4,13 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; +use core::time::Duration; use serde::{Deserialize, Serialize}; use crate::{ serde_anymap::{ArrayMut, Cptr}, tuples::{MatchNameAndType, MatchType, Named, TupleList}, + utils::current_time, AflError, }; @@ -22,7 +24,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st } /// Resets the observer - fn reset(&mut self) -> Result<(), AflError>; + fn pre_exec(&mut self) -> Result<(), AflError>; /// This function is executed after each fuzz run #[inline] @@ -48,11 +50,15 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st } } +/// A hastkel-style tuple of observers pub trait ObserversTuple: MatchNameAndType + MatchType + serde::Serialize + serde::de::DeserializeOwned { /// Reset all executors in the tuple - fn reset_all(&mut self) -> Result<(), AflError>; + /// This is called right before the next execution. + fn pre_exec_all(&mut self) -> Result<(), AflError>; + /// Do whatever you need to do after a run. + /// This is called right after the last execution fn post_exec_all(&mut self) -> Result<(), AflError>; //fn for_each(&self, f: fn(&dyn Observer)); //fn for_each_mut(&mut self, f: fn(&mut dyn Observer)); @@ -69,7 +75,7 @@ pub trait ObserversTuple: } impl ObserversTuple for () { - fn reset_all(&mut self) -> Result<(), AflError> { + fn pre_exec_all(&mut self) -> Result<(), AflError> { Ok(()) } fn post_exec_all(&mut self) -> Result<(), AflError> { @@ -85,9 +91,9 @@ where Head: Observer, Tail: ObserversTuple + TupleList, { - fn reset_all(&mut self) -> Result<(), AflError> { - self.0.reset()?; - self.1.reset_all() + fn pre_exec_all(&mut self) -> Result<(), AflError> { + self.0.pre_exec()?; + self.1.pre_exec_all() } fn post_exec_all(&mut self) -> Result<(), AflError> { @@ -106,6 +112,44 @@ where }*/ } +/// A simple observer, just overlooking the runtime of the target. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct TimeObserver { + name: String, + start_time: Duration, + last_runtime: Option, +} + +impl TimeObserver { + /// Creates a new TimeObserver with the given name. + pub fn new(name: &'static str) -> Self { + Self { + name: name.to_string(), + start_time: Duration::from_secs(0), + last_runtime: None, + } + } +} + +impl Observer for TimeObserver { + fn pre_exec(&mut self) -> Result<(), AflError> { + self.last_runtime = None; + self.start_time = current_time(); + Ok(()) + } + + fn post_exec(&mut self) -> Result<(), AflError> { + self.last_runtime = Some(current_time() - self.start_time); + Ok(()) + } +} + +impl Named for TimeObserver { + fn name(&self) -> &str { + &self.name + } +} + /// A MapObserver observes the static map, as oftentimes used for afl-like coverage information pub trait MapObserver: Observer where @@ -163,7 +207,7 @@ where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { #[inline] - fn reset(&mut self) -> Result<(), AflError> { + fn pre_exec(&mut self) -> Result<(), AflError> { self.reset_map() } } @@ -235,6 +279,7 @@ where } } +/// Overlooking a variable bitmap #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] pub struct VariableMapObserver @@ -252,7 +297,7 @@ where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { #[inline] - fn reset(&mut self) -> Result<(), AflError> { + fn pre_exec(&mut self) -> Result<(), AflError> { self.reset_map() } } @@ -340,17 +385,23 @@ where #[cfg(test)] mod tests { - use crate::observers::StdMapObserver; - use crate::tuples::Named; + use crate::{ + observers::{StdMapObserver, TimeObserver}, + tuples::{tuple_list, tuple_list_type, Named}, + }; static mut MAP: [u32; 4] = [0; 4]; #[test] fn test_observer_serde() { - let obv = StdMapObserver::new("test", unsafe { &mut MAP }); + let obv = tuple_list!( + TimeObserver::new("time"), + StdMapObserver::new("map", unsafe { &mut MAP }) + ); let vec = postcard::to_allocvec(&obv).unwrap(); println!("{:?}", vec); - let obv2: StdMapObserver = postcard::from_bytes(&vec).unwrap(); - assert_eq!(obv.name(), obv2.name()); + let obv2: tuple_list_type!(TimeObserver, StdMapObserver) = + postcard::from_bytes(&vec).unwrap(); + assert_eq!(obv.0.name(), obv2.0.name()); } } diff --git a/afl/src/tuples.rs b/afl/src/tuples.rs index 4b6dcfa20f..3163ee27f1 100644 --- a/afl/src/tuples.rs +++ b/afl/src/tuples.rs @@ -91,7 +91,9 @@ where } } +/// We need fixed names for many parts of this lib. pub trait Named { + /// Provide the name of this element. fn name(&self) -> &str; }