Observers refactor (#84)

* new observer structure with HasExecHooks

* adapt libafl_frida to new observers

* docstrings
This commit is contained in:
Andrea Fioraldi 2021-05-04 13:54:46 +02:00
parent 116a51270c
commit 9e9d95f93d
16 changed files with 343 additions and 379 deletions

View File

@ -77,7 +77,6 @@ pub fn main() {
// Create the executor for an in-process function with just one observer // Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"in-process(signals)",
&mut harness, &mut harness,
tuple_list!(observer), tuple_list!(observer),
&mut state, &mut state,

View File

@ -2,14 +2,15 @@
//! The example harness is built for libpng. //! The example harness is built for libpng.
use libafl::{ use libafl::{
bolts::tuples::{tuple_list, Named}, bolts::tuples::tuple_list,
corpus::{ corpus::{
ondisk::OnDiskMetadataFormat, Corpus, InMemoryCorpus, ondisk::OnDiskMetadataFormat, Corpus, InMemoryCorpus,
IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler,
}, },
events::{setup_restarting_mgr_std, EventManager}, events::setup_restarting_mgr_std,
executors::{ executors::{
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasObservers, inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasExecHooks,
HasExecHooksTuple, HasObservers, HasObserversHooks,
}, },
feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
@ -37,14 +38,14 @@ use libafl_frida::{
FridaOptions, FridaOptions,
}; };
struct FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT> struct FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple,
{ {
base: TimeoutExecutor<InProcessExecutor<'a, H, I, OT>, I, OT>, base: TimeoutExecutor<InProcessExecutor<'a, EM, H, I, OT, S>, I>,
/// Frida's dynamic rewriting engine /// Frida's dynamic rewriting engine
stalker: Stalker<'a>, stalker: Stalker<'a>,
/// User provided callback for instrumentation /// User provided callback for instrumentation
@ -53,19 +54,17 @@ where
_phantom: PhantomData<&'b u8>, _phantom: PhantomData<&'b u8>,
} }
impl<'a, 'b, 'c, FH, H, I, OT> Executor<I> for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT> impl<'a, 'b, 'c, EM, FH, H, I, OT, S> Executor<I>
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple,
{ {
/// Called right before exexution starts /// Instruct the target about the input and run
#[inline] #[inline]
fn pre_exec<EM, S>(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
where
EM: EventManager<I, S>,
{
if self.helper.stalker_enabled() { if self.helper.stalker_enabled() {
if !self.followed { if !self.followed {
self.followed = true; self.followed = true;
@ -77,15 +76,6 @@ where
)) ))
} }
} }
self.helper.pre_exec(input);
self.base.pre_exec(state, event_mgr, input)
}
/// Instruct the target about the input and run
#[inline]
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
let res = self.base.run_target(input); let res = self.base.run_target(input);
if unsafe { ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() } { if unsafe { ASAN_ERRORS.is_some() && !ASAN_ERRORS.as_ref().unwrap().is_empty() } {
println!("Crashing target as it had ASAN errors"); println!("Crashing target as it had ASAN errors");
@ -93,29 +83,38 @@ where
libc::raise(libc::SIGABRT); libc::raise(libc::SIGABRT);
} }
} }
if self.helper.stalker_enabled() {
self.stalker.deactivate();
}
res res
} }
}
impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasExecHooks<EM, I, S>
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where
FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes,
OT: ObserversTuple,
{
/// Called right before exexution starts
#[inline]
fn pre_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> {
self.helper.pre_exec(input);
self.base.pre_exec(state, event_mgr, input)
}
/// Called right after execution finished. /// Called right after execution finished.
#[inline] #[inline]
fn post_exec<EM, S>( fn post_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> {
&mut self,
state: &mut S,
event_mgr: &mut EM,
input: &I,
) -> Result<(), Error>
where
EM: EventManager<I, S>,
{
if self.helper.stalker_enabled() {
self.stalker.deactivate();
}
self.helper.post_exec(input); self.helper.post_exec(input);
self.base.post_exec(state, event_mgr, input) self.base.post_exec(state, event_mgr, input)
} }
} }
impl<'a, 'b, 'c, FH, H, I, OT> HasObservers<OT> for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT> impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasObservers<OT>
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
@ -133,19 +132,17 @@ where
} }
} }
impl<'a, 'b, 'c, FH, H, I, OT> Named for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT> impl<'a, 'b, 'c, EM, FH, H, I, OT, S> HasObserversHooks<EM, I, OT, S>
for FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
{ {
fn name(&self) -> &str {
self.base.name()
}
} }
impl<'a, 'b, 'c, FH, H, I, OT> FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT> impl<'a, 'b, 'c, EM, FH, H, I, OT, S> FridaInProcessExecutor<'a, 'b, 'c, EM, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
@ -154,7 +151,7 @@ where
{ {
pub fn new( pub fn new(
gum: &'a Gum, gum: &'a Gum,
base: InProcessExecutor<'a, H, I, OT>, base: InProcessExecutor<'a, EM, H, I, OT, S>,
helper: &'c mut FH, helper: &'c mut FH,
timeout: Duration, timeout: Duration,
) -> Self { ) -> Self {
@ -324,7 +321,6 @@ unsafe fn fuzz(
let mut executor = FridaInProcessExecutor::new( let mut executor = FridaInProcessExecutor::new(
&gum, &gum,
InProcessExecutor::new( InProcessExecutor::new(
"in-process(edges)",
&mut frida_harness, &mut frida_harness,
tuple_list!(edges_observer, AsanErrorsObserver::new(&ASAN_ERRORS)), tuple_list!(edges_observer, AsanErrorsObserver::new(&ASAN_ERRORS)),
&mut state, &mut state,

View File

@ -113,7 +113,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Create the executor for an in-process function with observers for edge coverage, value-profile and allocations sizes // Create the executor for an in-process function with observers for edge coverage, value-profile and allocations sizes
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"in-process(edges,cmp,alloc)",
&mut harness, &mut harness,
tuple_list!(edges_observer, cmps_observer, allocs_observer), tuple_list!(edges_observer, cmps_observer, allocs_observer),
&mut state, &mut state,

View File

@ -120,7 +120,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time // Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = TimeoutExecutor::new( let mut executor = TimeoutExecutor::new(
InProcessExecutor::new( InProcessExecutor::new(
"in-process(edges,time)",
&mut harness, &mut harness,
tuple_list!(edges_observer, TimeObserver::new("time")), tuple_list!(edges_observer, TimeObserver::new("time")),
&mut state, &mut state,

View File

@ -116,7 +116,6 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Create the executor for an in-process function with just one observer for edge coverage // Create the executor for an in-process function with just one observer for edge coverage
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"in-process(edges,time)",
&mut harness, &mut harness,
tuple_list!(edges_observer, TimeObserver::new("time")), tuple_list!(edges_observer, TimeObserver::new("time")),
&mut state, &mut state,

View File

@ -14,10 +14,11 @@ use crate::bolts::os::unix_signals::setup_signal_handler;
use crate::bolts::os::windows_exceptions::setup_exception_handler; use crate::bolts::os::windows_exceptions::setup_exception_handler;
use crate::{ use crate::{
bolts::tuples::Named,
corpus::Corpus, corpus::Corpus,
events::EventManager, events::EventManager,
executors::{Executor, ExitKind, HasObservers}, executors::{
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
},
feedbacks::FeedbacksTuple, feedbacks::FeedbacksTuple,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
@ -26,34 +27,41 @@ use crate::{
}; };
/// The inmem executor simply calls a target function, then returns afterwards. /// The inmem executor simply calls a target function, then returns afterwards.
pub struct InProcessExecutor<'a, H, I, OT> pub struct InProcessExecutor<'a, EM, H, I, OT, S>
where where
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple,
{ {
/// The name of this executor instance, to address it from other components
name: &'static str,
/// The harness function, being executed for each fuzzing loop execution /// The harness function, being executed for each fuzzing loop execution
harness_fn: &'a mut H, harness_fn: &'a mut H,
/// The observers, observing each run /// The observers, observing each run
observers: OT, observers: OT,
phantom: PhantomData<I>, phantom: PhantomData<(EM, I, S)>,
} }
impl<'a, H, I, OT> Executor<I> for InProcessExecutor<'a, H, I, OT> impl<'a, EM, H, I, OT, S> Executor<I> for InProcessExecutor<'a, EM, H, I, OT, S>
where where
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple,
{ {
#[inline] #[inline]
fn pre_exec<EM, S>( fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
&mut self, let bytes = input.target_bytes();
_state: &mut S, let ret = (self.harness_fn)(bytes.as_slice());
_event_mgr: &mut EM, Ok(ret)
_input: &I, }
) -> Result<(), Error> { }
impl<'a, EM, H, I, OT, S> HasExecHooks<EM, I, S> for InProcessExecutor<'a, EM, H, I, OT, S>
where
H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes,
OT: ObserversTuple,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
let data = &mut unix_signal_handler::GLOBAL_STATE; let data = &mut unix_signal_handler::GLOBAL_STATE;
@ -92,19 +100,7 @@ where
} }
#[inline] #[inline]
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> { fn post_exec(&mut self, _state: &mut S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> {
let bytes = input.target_bytes();
let ret = (self.harness_fn)(bytes.as_slice());
Ok(ret)
}
#[inline]
fn post_exec<EM, S>(
&mut self,
_state: &mut S,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
write_volatile( write_volatile(
@ -125,18 +121,7 @@ where
} }
} }
impl<'a, H, I, OT> Named for InProcessExecutor<'a, H, I, OT> impl<'a, EM, H, I, OT, S> HasObservers<OT> for InProcessExecutor<'a, EM, H, I, OT, S>
where
H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes,
OT: ObserversTuple,
{
fn name(&self) -> &str {
self.name
}
}
impl<'a, H, I, OT> HasObservers<OT> for InProcessExecutor<'a, H, I, OT>
where where
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
@ -153,7 +138,15 @@ where
} }
} }
impl<'a, H, I, OT> InProcessExecutor<'a, H, I, OT> impl<'a, EM, H, I, OT, S> HasObserversHooks<EM, I, OT, S> for InProcessExecutor<'a, EM, H, I, OT, S>
where
H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
{
}
impl<'a, EM, H, I, OT, S> InProcessExecutor<'a, EM, H, I, OT, S>
where where
H: FnMut(&[u8]) -> ExitKind, H: FnMut(&[u8]) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
@ -162,12 +155,10 @@ where
/// Create a new in mem executor. /// Create a new in mem executor.
/// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used,
/// depending on different corpus or state. /// depending on different corpus or state.
/// * `name` - the name of this executor (to address it along the way)
/// * `harness_fn` - the harness, executiong the function /// * `harness_fn` - the harness, executiong the function
/// * `observers` - the observers observing the target during execution /// * `observers` - the observers observing the target during execution
/// This may return an error on unix, if signal handler setup fails /// This may return an error on unix, if signal handler setup fails
pub fn new<EM, OC, OFT, S>( pub fn new<OC, OFT>(
name: &'static str,
harness_fn: &'a mut H, harness_fn: &'a mut H,
observers: OT, observers: OT,
_state: &mut S, _state: &mut S,
@ -213,7 +204,6 @@ where
Ok(Self { Ok(Self {
harness_fn, harness_fn,
observers, observers,
name,
phantom: PhantomData, phantom: PhantomData,
}) })
} }
@ -696,10 +686,9 @@ mod tests {
fn test_inmem_exec() { fn test_inmem_exec() {
let mut harness = |_buf: &[u8]| ExitKind::Ok; let mut harness = |_buf: &[u8]| ExitKind::Ok;
let mut in_process_executor = InProcessExecutor::<_, NopInput, ()> { let mut in_process_executor = InProcessExecutor::<(), _, NopInput, (), ()> {
harness_fn: &mut harness, harness_fn: &mut harness,
observers: tuple_list!(), observers: tuple_list!(),
name: "main",
phantom: PhantomData, phantom: PhantomData,
}; };
let mut input = NopInput {}; let mut input = NopInput {};

View File

@ -8,8 +8,7 @@ pub use timeout::TimeoutExecutor;
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{ use crate::{
bolts::{serdeany::SerdeAny, tuples::Named}, bolts::serdeany::SerdeAny,
events::EventManager,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
@ -29,6 +28,57 @@ pub enum ExitKind {
Custom(Box<dyn CustomExitKind>), Custom(Box<dyn CustomExitKind>),
} }
/// Pre and post exec hooks
pub trait HasExecHooks<EM, I, S> {
/// Called right before exexution starts
#[inline]
fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
/// Called right after execution finished.
#[inline]
fn post_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
}
/// A haskell-style tuple of objects that have pre and post exec hooks
pub trait HasExecHooksTuple<EM, I, S> {
/// This is called right before the next execution.
fn pre_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error>;
/// This is called right after the last execution
fn post_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error>;
}
impl<EM, I, S> HasExecHooksTuple<EM, I, S> for () {
fn pre_exec_all(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
Ok(())
}
}
impl<EM, I, S, Head, Tail> HasExecHooksTuple<EM, I, S> for (Head, Tail)
where
Head: HasExecHooks<EM, I, S>,
Tail: HasExecHooksTuple<EM, I, S>,
{
fn pre_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.0.pre_exec(state, mgr, input)?;
self.1.pre_exec_all(state, mgr, input)
}
fn post_exec_all(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.0.post_exec(state, mgr, input)?;
self.1.post_exec_all(state, mgr, input)
}
}
/// Holds a tuple of Observers
pub trait HasObservers<OT> pub trait HasObservers<OT>
where where
OT: ObserversTuple, OT: ObserversTuple,
@ -38,27 +88,41 @@ where
/// Get the linked observers /// Get the linked observers
fn observers_mut(&mut self) -> &mut OT; fn observers_mut(&mut self) -> &mut OT;
}
/// Reset the state of all the observes linked to this executor /// Execute the exec hooks of the observers if they all implement HasExecHooks
pub trait HasObserversHooks<EM, I, OT, S>: HasObservers<OT>
where
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
{
#[inline] #[inline]
fn pre_exec_observers(&mut self) -> Result<(), Error> { fn pre_exec_observers(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.observers_mut().pre_exec_all() self.observers_mut().pre_exec_all(state, mgr, input)
} }
/// Run the post exec hook for all the observes linked to this executor /// Run the post exec hook for all the observes linked to this executor
#[inline] #[inline]
fn post_exec_observers(&mut self) -> Result<(), Error> { fn post_exec_observers(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.observers_mut().post_exec_all() self.observers_mut().post_exec_all(state, mgr, input)
} }
} }
/// An executor takes the given inputs, and runs the harness/target.
pub trait Executor<I>
where
I: Input,
{
/// Instruct the target about the input and run
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error>;
}
/// A simple executor that does nothing. /// A simple executor that does nothing.
/// If intput len is 0, `run_target` will return Err /// If intput len is 0, `run_target` will return Err
struct NopExecutor<I> { struct NopExecutor<EM, I, S> {
phantom: PhantomData<I>, phantom: PhantomData<(EM, I, S)>,
} }
impl<I> Executor<I> for NopExecutor<I> impl<EM, I, S> Executor<I> for NopExecutor<EM, I, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
{ {
@ -71,48 +135,7 @@ where
} }
} }
impl<I> Named for NopExecutor<I> { impl<EM, I, S> HasExecHooks<EM, I, S> for NopExecutor<EM, I, S> where I: Input + HasTargetBytes {}
fn name(&self) -> &str {
&"NopExecutor"
}
}
/// An executor takes the given inputs, and runs the harness/target.
pub trait Executor<I>: Named
where
I: Input,
{
/// Called right before exexution starts
#[inline]
fn pre_exec<EM, S>(
&mut self,
_state: &mut S,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), Error>
where
EM: EventManager<I, S>,
{
Ok(())
}
/// Called right after execution finished.
#[inline]
fn post_exec<EM, S>(
&mut self,
_state: &mut S,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), Error>
where
EM: EventManager<I, S>,
{
Ok(())
}
/// Instruct the target about the input and run
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error>;
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
@ -125,7 +148,7 @@ mod test {
fn nop_executor() { fn nop_executor() {
let empty_input = BytesInput::new(vec![]); let empty_input = BytesInput::new(vec![]);
let nonempty_input = BytesInput::new(vec![1u8]); let nonempty_input = BytesInput::new(vec![1u8]);
let mut executor = NopExecutor { let mut executor = NopExecutor::<(), _, ()> {
phantom: PhantomData, phantom: PhantomData,
}; };
assert!(executor.run_target(&empty_input).is_err()); assert!(executor.run_target(&empty_input).is_err());

View File

@ -3,10 +3,10 @@
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
use crate::{ use crate::{
bolts::tuples::Named, executors::{
events::EventManager, Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
executors::{Executor, ExitKind, HasObservers}, },
inputs::{HasTargetBytes, Input}, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
}; };
@ -39,50 +39,20 @@ extern "C" {
const ITIMER_REAL: c_int = 0; const ITIMER_REAL: c_int = 0;
/// The timeout excutor is a wrapper that set a timeout before each run /// The timeout excutor is a wrapper that set a timeout before each run
pub struct TimeoutExecutor<E, I, OT> pub struct TimeoutExecutor<E, I>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I>,
I: Input + HasTargetBytes, I: Input,
OT: ObserversTuple,
{ {
executor: E, executor: E,
exec_tmout: Duration, exec_tmout: Duration,
phantom: PhantomData<(I, OT)>, phantom: PhantomData<I>,
} }
impl<E, I, OT> Named for TimeoutExecutor<E, I, OT> impl<E, I> TimeoutExecutor<E, I>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I>,
I: Input + HasTargetBytes, I: Input,
OT: ObserversTuple,
{
fn name(&self) -> &str {
self.executor.name()
}
}
impl<E, I, OT> HasObservers<OT> for TimeoutExecutor<E, I, OT>
where
E: Executor<I> + HasObservers<OT>,
I: Input + HasTargetBytes,
OT: ObserversTuple,
{
#[inline]
fn observers(&self) -> &OT {
self.executor.observers()
}
#[inline]
fn observers_mut(&mut self) -> &mut OT {
self.executor.observers_mut()
}
}
impl<E, I, OT> TimeoutExecutor<E, I, OT>
where
E: Executor<I> + HasObservers<OT>,
I: Input + HasTargetBytes,
OT: ObserversTuple,
{ {
pub fn new(executor: E, exec_tmout: Duration) -> Self { pub fn new(executor: E, exec_tmout: Duration) -> Self {
Self { Self {
@ -97,19 +67,48 @@ where
} }
} }
impl<E, I, OT> Executor<I> for TimeoutExecutor<E, I, OT> impl<E, I> Executor<I> for TimeoutExecutor<E, I>
where
E: Executor<I>,
I: Input,
{
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
self.executor.run_target(input)
}
}
impl<E, I, OT> HasObservers<OT> for TimeoutExecutor<E, I>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
I: Input + HasTargetBytes, I: Input,
OT: ObserversTuple, OT: ObserversTuple,
{ {
#[inline] #[inline]
fn pre_exec<EM: EventManager<I, S>, S>( fn observers(&self) -> &OT {
&mut self, self.executor.observers()
_state: &mut S, }
_event_mgr: &mut EM,
_input: &I, #[inline]
) -> Result<(), Error> { fn observers_mut(&mut self) -> &mut OT {
self.executor.observers_mut()
}
}
impl<E, EM, I, OT, S> HasObserversHooks<EM, I, OT, S> for TimeoutExecutor<E, I>
where
E: Executor<I> + HasObservers<OT>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
{
}
impl<E, EM, I, S> HasExecHooks<EM, I, S> for TimeoutExecutor<E, I>
where
E: Executor<I> + HasExecHooks<EM, I, S>,
I: Input,
{
#[inline]
fn pre_exec(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
let milli_sec = self.exec_tmout.as_millis(); let milli_sec = self.exec_tmout.as_millis();
@ -135,16 +134,11 @@ where
// TODO // TODO
let _ = self.exec_tmout.as_millis(); let _ = self.exec_tmout.as_millis();
} }
self.executor.pre_exec(_state, _event_mgr, _input) self.executor.pre_exec(state, mgr, input)
} }
#[inline] #[inline]
fn post_exec<EM: EventManager<I, S>, S>( fn post_exec(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
&mut self,
_state: &mut S,
_event_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
let it_value = Timeval { let it_value = Timeval {
@ -168,10 +162,6 @@ where
{ {
// TODO // TODO
} }
self.executor.post_exec(_state, _event_mgr, _input) self.executor.post_exec(state, mgr, input)
}
fn run_target(&mut self, input: &I) -> Result<ExitKind, Error> {
self.executor.run_target(input)
} }
} }

View File

@ -14,14 +14,14 @@ use crate::{
executors::ExitKind, executors::ExitKind,
feedbacks::Feedback, feedbacks::Feedback,
inputs::Input, inputs::Input,
observers::{MapObserver, Observer, ObserversTuple}, observers::{MapObserver, ObserversTuple},
state::HasMetadata, state::HasMetadata,
utils::AsSlice, utils::AsSlice,
Error, Error,
}; };
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>; pub type MaxMapFeedback<O, T> = MapFeedback<O, MaxReducer, T>;
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>; pub type MinMapFeedback<O, T> = MapFeedback<O, MinReducer, T>;
/// A Reducer function is used to aggregate values for the novelty search /// A Reducer function is used to aggregate values for the novelty search
pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static
@ -32,14 +32,9 @@ where
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MaxReducer<T> pub struct MaxReducer {}
where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
phantom: PhantomData<T>,
}
impl<T> Reducer<T> for MaxReducer<T> impl<T> Reducer<T> for MaxReducer
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{ {
@ -54,14 +49,9 @@ where
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MinReducer<T> pub struct MinReducer {}
where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{
phantom: PhantomData<T>,
}
impl<T> Reducer<T> for MinReducer<T> impl<T> Reducer<T> for MinReducer
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{ {
@ -119,7 +109,7 @@ impl MapNoveltiesMetadata {
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct MapFeedback<T, R, O> pub struct MapFeedback<O, R, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -137,25 +127,22 @@ where
phantom: PhantomData<(R, O)>, phantom: PhantomData<(R, O)>,
} }
impl<T, R, O, I> Feedback<I> for MapFeedback<T, R, O> impl<O, R, T, I> Feedback<I> for MapFeedback<O, R, T>
where where
T: Integer T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
+ Default
+ Copy
+ 'static
+ serde::Serialize
+ serde::de::DeserializeOwned
+ core::fmt::Debug,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<T>, O: MapObserver<T>,
I: Input, I: Input,
{ {
fn is_interesting<OT: ObserversTuple>( fn is_interesting<OT>(
&mut self, &mut self,
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<u32, Error>
where
OT: ObserversTuple,
{
let mut interesting = 0; let mut interesting = 0;
// TODO optimize // TODO optimize
let observer = observers.match_name_type::<O>(&self.name).unwrap(); let observer = observers.match_name_type::<O>(&self.name).unwrap();
@ -243,7 +230,7 @@ where
} }
} }
impl<T, R, O> Named for MapFeedback<T, R, O> impl<O, R, T> Named for MapFeedback<O, R, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -255,11 +242,11 @@ where
} }
} }
impl<T, R, O> MapFeedback<T, R, O> impl<O, R, T> MapFeedback<O, R, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
O: MapObserver<T> + Observer, O: MapObserver<T>,
{ {
/// Create new `MapFeedback` /// Create new `MapFeedback`
pub fn new(name: &'static str, map_size: usize) -> Self { pub fn new(name: &'static str, map_size: usize) -> Self {
@ -315,7 +302,7 @@ where
} }
} }
impl<T, R, O> MapFeedback<T, R, O> impl<O, R, T> MapFeedback<O, R, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,

View File

@ -25,12 +25,14 @@ where
I: Input, I: Input,
{ {
/// `is_interesting ` should return the "Interestingness" from 0 to 255 (percent times 2.55) /// `is_interesting ` should return the "Interestingness" from 0 to 255 (percent times 2.55)
fn is_interesting<OT: ObserversTuple>( fn is_interesting<OT>(
&mut self, &mut self,
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error>; ) -> Result<u32, Error>
where
OT: ObserversTuple;
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item
#[inline] #[inline]
@ -50,12 +52,14 @@ where
I: Input, I: Input,
{ {
/// Get the total interestingness value from all feedbacks /// Get the total interestingness value from all feedbacks
fn is_interesting_all<OT: ObserversTuple>( fn is_interesting_all<OT>(
&mut self, &mut self,
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error>; ) -> Result<u32, Error>
where
OT: ObserversTuple;
/// Write metadata for this testcase /// Write metadata for this testcase
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error>; fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error>;
@ -69,12 +73,10 @@ where
I: Input, I: Input,
{ {
#[inline] #[inline]
fn is_interesting_all<OT: ObserversTuple>( fn is_interesting_all<OT>(&mut self, _: &I, _: &OT, _: &ExitKind) -> Result<u32, Error>
&mut self, where
_: &I, OT: ObserversTuple,
_: &OT, {
_: &ExitKind,
) -> Result<u32, Error> {
Ok(0) Ok(0)
} }
@ -95,12 +97,15 @@ where
Tail: FeedbacksTuple<I>, Tail: FeedbacksTuple<I>,
I: Input, I: Input,
{ {
fn is_interesting_all<OT: ObserversTuple>( fn is_interesting_all<OT>(
&mut self, &mut self,
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<u32, Error>
where
OT: ObserversTuple,
{
Ok(self.0.is_interesting(input, observers, exit_kind)? Ok(self.0.is_interesting(input, observers, exit_kind)?
+ self.1.is_interesting_all(input, observers, exit_kind)?) + self.1.is_interesting_all(input, observers, exit_kind)?)
} }
@ -124,12 +129,15 @@ impl<I> Feedback<I> for CrashFeedback
where where
I: Input, I: Input,
{ {
fn is_interesting<OT: ObserversTuple>( fn is_interesting<OT>(
&mut self, &mut self,
_input: &I, _input: &I,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<u32, Error>
where
OT: ObserversTuple,
{
if let ExitKind::Crash = exit_kind { if let ExitKind::Crash = exit_kind {
Ok(1) Ok(1)
} else { } else {
@ -164,12 +172,15 @@ impl<I> Feedback<I> for TimeoutFeedback
where where
I: Input, I: Input,
{ {
fn is_interesting<OT: ObserversTuple>( fn is_interesting<OT>(
&mut self, &mut self,
_input: &I, _input: &I,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<u32, Error>
where
OT: ObserversTuple,
{
if let ExitKind::Timeout = exit_kind { if let ExitKind::Timeout = exit_kind {
Ok(1) Ok(1)
} else { } else {
@ -207,12 +218,15 @@ impl<I> Feedback<I> for TimeFeedback
where where
I: Input, I: Input,
{ {
fn is_interesting<OT: ObserversTuple>( fn is_interesting<OT>(
&mut self, &mut self,
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<u32, Error>
where
OT: ObserversTuple,
{
let observer = observers.match_first_type::<TimeObserver>().unwrap(); let observer = observers.match_first_type::<TimeObserver>().unwrap();
self.exec_time = *observer.last_runtime(); self.exec_time = *observer.last_runtime();
Ok(0) Ok(0)

View File

@ -194,7 +194,6 @@ mod tests {
let mut harness = |_buf: &[u8]| ExitKind::Ok; let mut harness = |_buf: &[u8]| ExitKind::Ok;
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"main",
&mut harness, &mut harness,
tuple_list!(), tuple_list!(),
//Box::new(|_, _, _, _, _| ()), //Box::new(|_, _, _, _, _| ()),

View File

@ -11,6 +11,7 @@ use crate::{
ownedref::{OwnedArrayPtrMut, OwnedPtr}, ownedref::{OwnedArrayPtrMut, OwnedPtr},
tuples::Named, tuples::Named,
}, },
executors::HasExecHooks,
observers::Observer, observers::Observer,
Error, Error,
}; };
@ -68,12 +69,18 @@ where
name: String, name: String,
} }
impl<T> Observer for StdMapObserver<T> impl<T> Observer for StdMapObserver<T> where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
{
}
impl<EM, I, S, T> HasExecHooks<EM, I, S> for StdMapObserver<T>
where where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
Self: MapObserver<T>,
{ {
#[inline] #[inline]
fn pre_exec(&mut self) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -170,12 +177,17 @@ where
name: String, name: String,
} }
impl<T> Observer for VariableMapObserver<T> impl<T> Observer for VariableMapObserver<T> where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
{
}
impl<EM, I, S, T> HasExecHooks<EM, I, S> for VariableMapObserver<T>
where where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
{ {
#[inline] #[inline]
fn pre_exec(&mut self) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -264,7 +276,7 @@ where
#[serde(bound = "M: serde::de::DeserializeOwned")] #[serde(bound = "M: serde::de::DeserializeOwned")]
pub struct HitcountsMapObserver<M> pub struct HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: serde::Serialize + serde::de::DeserializeOwned,
{ {
base: M, base: M,
} }
@ -284,27 +296,29 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
]; ];
impl<M> Observer for HitcountsMapObserver<M> impl<M> Observer for HitcountsMapObserver<M> where M: MapObserver<u8> {}
impl<EM, I, S, M> HasExecHooks<EM, I, S> for HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: MapObserver<u8> + HasExecHooks<EM, I, S>,
{ {
#[inline] #[inline]
fn pre_exec(&mut self) -> Result<(), Error> { fn pre_exec(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
self.reset_map() self.base.pre_exec(state, mgr, input)
} }
#[inline] #[inline]
fn post_exec(&mut self) -> Result<(), Error> { fn post_exec(&mut self, state: &mut S, mgr: &mut EM, input: &I) -> Result<(), Error> {
for x in self.map_mut().iter_mut() { for x in self.map_mut().iter_mut() {
*x = COUNT_CLASS_LOOKUP[*x as usize]; *x = COUNT_CLASS_LOOKUP[*x as usize];
} }
Ok(()) self.base.post_exec(state, mgr, input)
} }
} }
impl<M> Named for HitcountsMapObserver<M> impl<M> Named for HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: Named + serde::Serialize + serde::de::DeserializeOwned,
{ {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
@ -349,7 +363,7 @@ where
impl<M> HitcountsMapObserver<M> impl<M> HitcountsMapObserver<M>
where where
M: MapObserver<u8>, M: serde::Serialize + serde::de::DeserializeOwned,
{ {
/// Creates a new MapObserver /// Creates a new MapObserver
pub fn new(base: M) -> Self { pub fn new(base: M) -> Self {

View File

@ -3,15 +3,13 @@
pub mod map; pub mod map;
pub use map::*; pub use map::*;
use alloc::{ use alloc::string::{String, ToString};
string::{String, ToString},
vec::Vec,
};
use core::time::Duration; use core::time::Duration;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named}, bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named},
executors::HasExecHooks,
utils::current_time, utils::current_time,
Error, Error,
}; };
@ -20,74 +18,26 @@ use crate::{
/// They can then be used by various sorts of feedback. /// They can then be used by various sorts of feedback.
pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static { pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static {
/// The testcase finished execution, calculate any changes. /// The testcase finished execution, calculate any changes.
/// Reserved for future use.
#[inline] #[inline]
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Resets the observer
fn pre_exec(&mut self) -> Result<(), Error>;
/// This function is executed after each fuzz run
#[inline]
fn post_exec(&mut self) -> Result<(), Error> {
Ok(())
}
/// Serialize this observer's state only, to be restored later using deserialize_state
/// As opposed to completely serializing the observer, this is only needed when the fuzzer is to be restarted
/// If no state is needed to be kept, just return an empty vec.
/// Example:
/// >> The virgin_bits map in AFL needs to be in sync with the corpus
#[inline]
fn serialize_state(&mut self) -> Result<Vec<u8>, Error> {
Ok(vec![])
}
/// Restore the state from a given vec, priviously stored using `serialize_state`
#[inline]
fn deserialize_state(&mut self, serialized_state: &[u8]) -> Result<(), Error> {
let _ = serialized_state;
Ok(())
}
} }
/// A hastkel-style tuple of observers /// A haskell-style tuple of observers
pub trait ObserversTuple: pub trait ObserversTuple:
MatchNameAndType + MatchType + MatchFirstType + serde::Serialize + serde::de::DeserializeOwned MatchNameAndType + MatchType + MatchFirstType + serde::Serialize + serde::de::DeserializeOwned
{ {
/// Reset all executors in the tuple
/// This is called right before the next execution.
fn pre_exec_all(&mut self) -> Result<(), Error>;
/// Do whatever you need to do after a run.
/// This is called right after the last execution
fn post_exec_all(&mut self) -> Result<(), Error>;
} }
impl ObserversTuple for () { impl ObserversTuple for () {}
fn pre_exec_all(&mut self) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(&mut self) -> Result<(), Error> {
Ok(())
}
}
impl<Head, Tail> ObserversTuple for (Head, Tail) impl<Head, Tail> ObserversTuple for (Head, Tail)
where where
Head: Observer, Head: Observer,
Tail: ObserversTuple, Tail: ObserversTuple,
{ {
fn pre_exec_all(&mut self) -> Result<(), Error> {
self.0.pre_exec()?;
self.1.pre_exec_all()
}
fn post_exec_all(&mut self) -> Result<(), Error> {
self.0.post_exec()?;
self.1.post_exec_all()
}
} }
/// A simple observer, just overlooking the runtime of the target. /// A simple observer, just overlooking the runtime of the target.
@ -113,14 +63,16 @@ impl TimeObserver {
} }
} }
impl Observer for TimeObserver { impl Observer for TimeObserver {}
fn pre_exec(&mut self) -> Result<(), Error> {
impl<EM, I, S> HasExecHooks<EM, I, S> for TimeObserver {
fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
self.last_runtime = None; self.last_runtime = None;
self.start_time = current_time(); self.start_time = current_time();
Ok(()) Ok(())
} }
fn post_exec(&mut self) -> Result<(), Error> { fn post_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
self.last_runtime = Some(current_time() - self.start_time); self.last_runtime = Some(current_time() - self.start_time);
Ok(()) Ok(())
} }

View File

@ -3,7 +3,7 @@ use core::marker::PhantomData;
use crate::{ use crate::{
corpus::{Corpus, CorpusScheduler}, corpus::{Corpus, CorpusScheduler},
events::EventManager, events::EventManager,
executors::{Executor, HasObservers}, executors::{Executor, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks},
inputs::Input, inputs::Input,
mutators::Mutator, mutators::Mutator,
observers::ObserversTuple, observers::ObserversTuple,
@ -25,8 +25,8 @@ where
S: HasCorpus<C, I> + Evaluator<I>, S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT> + HasExecHooks<EM, I, S> + HasObserversHooks<EM, I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
{ {
/// The mutator registered for this stage /// The mutator registered for this stage
@ -76,8 +76,8 @@ where
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT> + HasExecHooks<EM, I, S> + HasObserversHooks<EM, I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
R: Rand, R: Rand,
{ {
@ -94,8 +94,8 @@ where
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT> + HasExecHooks<EM, I, S> + HasObserversHooks<EM, I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
R: Rand, R: Rand,
{ {
@ -125,8 +125,8 @@ where
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT> + HasExecHooks<EM, I, S> + HasObserversHooks<EM, I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
R: Rand, R: Rand,
{ {
@ -150,8 +150,8 @@ where
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT> + HasExecHooks<EM, I, S> + HasObserversHooks<EM, I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple + HasExecHooksTuple<EM, I, S>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
R: Rand, R: Rand,
{ {

View File

@ -12,7 +12,9 @@ use crate::{
bolts::serdeany::{SerdeAny, SerdeAnyMap}, bolts::serdeany::{SerdeAny, SerdeAnyMap},
corpus::{Corpus, CorpusScheduler, Testcase}, corpus::{Corpus, CorpusScheduler, Testcase},
events::{Event, EventManager, LogSeverity}, events::{Event, EventManager, LogSeverity},
executors::{Executor, ExitKind, HasObservers}, executors::{
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
},
feedbacks::FeedbacksTuple, feedbacks::FeedbacksTuple,
generators::Generator, generators::Generator,
inputs::Input, inputs::Input,
@ -97,7 +99,7 @@ pub trait HasMetadata {
} }
/// Trait for elements offering a feedbacks tuple /// Trait for elements offering a feedbacks tuple
pub trait HasFeedbacks<FT, I> pub trait HasFeedbacks<FT, I>: Sized
where where
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
@ -107,29 +109,10 @@ where
/// The feedbacks tuple (mut) /// The feedbacks tuple (mut)
fn feedbacks_mut(&mut self) -> &mut FT; fn feedbacks_mut(&mut self) -> &mut FT;
/// Resets all metadata holds by feedbacks
#[inline]
fn discard_feedbacks_metadata(&mut self, input: &I) -> Result<(), Error> {
// TODO: This could probably be automatic in the feedback somehow?
self.feedbacks_mut().discard_metadata_all(&input)
}
/// Creates a new testcase, appending the metadata from each feedback
#[inline]
fn testcase_with_feedbacks_metadata(
&mut self,
input: I,
fitness: u32,
) -> Result<Testcase<I>, Error> {
let mut testcase = Testcase::with_fitness(input, fitness);
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
Ok(testcase)
}
} }
/// Trait for elements offering an objective feedbacks tuple /// Trait for elements offering an objective feedbacks tuple
pub trait HasObjectives<FT, I> pub trait HasObjectives<FT, I>: Sized
where where
FT: FeedbacksTuple<I>, FT: FeedbacksTuple<I>,
I: Input, I: Input,
@ -160,7 +143,7 @@ pub trait HasStartTime {
} }
/// Add to the state if interesting /// Add to the state if interesting
pub trait IfInteresting<I> pub trait IfInteresting<I>: Sized
where where
I: Input, I: Input,
{ {
@ -200,8 +183,11 @@ where
scheduler: &CS, scheduler: &CS,
) -> Result<(u32, Option<usize>), Error> ) -> Result<(u32, Option<usize>), Error>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, I, Self>
+ HasObserversHooks<EM, I, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, Self>,
EM: EventManager<I, Self>, EM: EventManager<I, Self>,
CS: CorpusScheduler<I, Self>; CS: CorpusScheduler<I, Self>;
} }
@ -469,12 +455,13 @@ where
CS: CorpusScheduler<I, Self>, CS: CorpusScheduler<I, Self>,
{ {
if fitness > 0 { if fitness > 0 {
let testcase = self.testcase_with_feedbacks_metadata(input.clone(), fitness)?; let mut testcase = Testcase::with_fitness(input.clone(), fitness);
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
let idx = self.corpus.add(testcase)?; let idx = self.corpus.add(testcase)?;
scheduler.on_add(self, idx)?; scheduler.on_add(self, idx)?;
Ok(Some(idx)) Ok(Some(idx))
} else { } else {
self.discard_feedbacks_metadata(input)?; self.feedbacks_mut().discard_metadata_all(&input)?;
Ok(None) Ok(None)
} }
} }
@ -500,8 +487,11 @@ where
scheduler: &CS, scheduler: &CS,
) -> Result<(u32, Option<usize>), Error> ) -> Result<(u32, Option<usize>), Error>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, I, Self>
+ HasObserversHooks<EM, I, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, Self>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, Self>, EM: EventManager<I, Self>,
CS: CorpusScheduler<I, Self>, CS: CorpusScheduler<I, Self>,
@ -555,8 +545,11 @@ where
in_dir: &Path, in_dir: &Path,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<BytesInput> + HasObservers<OT>, E: Executor<BytesInput>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, BytesInput, Self>
+ HasObserversHooks<EM, BytesInput, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, BytesInput, Self>,
EM: EventManager<BytesInput, Self>, EM: EventManager<BytesInput, Self>,
CS: CorpusScheduler<BytesInput, Self>, CS: CorpusScheduler<BytesInput, Self>,
{ {
@ -601,8 +594,11 @@ where
in_dirs: &[PathBuf], in_dirs: &[PathBuf],
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<BytesInput> + HasObservers<OT>, E: Executor<BytesInput>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, BytesInput, Self>
+ HasObserversHooks<EM, BytesInput, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, BytesInput, Self>,
EM: EventManager<BytesInput, Self>, EM: EventManager<BytesInput, Self>,
CS: CorpusScheduler<BytesInput, Self>, CS: CorpusScheduler<BytesInput, Self>,
{ {
@ -639,19 +635,22 @@ where
event_mgr: &mut EM, event_mgr: &mut EM,
) -> Result<(u32, bool), Error> ) -> Result<(u32, bool), Error>
where where
E: Executor<I> + HasObservers<OT>, E: Executor<I>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, I, Self>
+ HasObserversHooks<EM, I, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, Self>,
C: Corpus<I>, C: Corpus<I>,
EM: EventManager<I, Self>, EM: EventManager<I, Self>,
{ {
executor.pre_exec_observers()?; executor.pre_exec_observers(self, event_mgr, input)?;
executor.pre_exec(self, event_mgr, input)?; executor.pre_exec(self, event_mgr, input)?;
let exit_kind = executor.run_target(input)?; let exit_kind = executor.run_target(input)?;
executor.post_exec(self, event_mgr, input)?; executor.post_exec(self, event_mgr, input)?;
*self.executions_mut() += 1; *self.executions_mut() += 1;
executor.post_exec_observers()?; executor.post_exec_observers(self, event_mgr, input)?;
let observers = executor.observers(); let observers = executor.observers();
let fitness = self let fitness = self
@ -676,8 +675,11 @@ where
where where
G: Generator<I, R>, G: Generator<I, R>,
C: Corpus<I>, C: Corpus<I>,
E: Executor<I> + HasObservers<OT>, E: Executor<I>
OT: ObserversTuple, + HasObservers<OT>
+ HasExecHooks<EM, I, Self>
+ HasObserversHooks<EM, I, OT, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, Self>,
EM: EventManager<I, Self>, EM: EventManager<I, Self>,
CS: CorpusScheduler<I, Self>, CS: CorpusScheduler<I, Self>,
{ {

View File

@ -2,7 +2,7 @@ use hashbrown::HashMap;
use libafl::{ use libafl::{
bolts::{ownedref::OwnedPtr, tuples::Named}, bolts::{ownedref::OwnedPtr, tuples::Named},
corpus::Testcase, corpus::Testcase,
executors::{CustomExitKind, ExitKind}, executors::{CustomExitKind, ExitKind, HasExecHooks},
feedbacks::Feedback, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::{Observer, ObserversTuple}, observers::{Observer, ObserversTuple},
@ -1625,8 +1625,10 @@ pub struct AsanErrorsObserver {
errors: OwnedPtr<Option<AsanErrors>>, errors: OwnedPtr<Option<AsanErrors>>,
} }
impl Observer for AsanErrorsObserver { impl Observer for AsanErrorsObserver {}
fn pre_exec(&mut self) -> Result<(), Error> {
impl<EM, I, S> HasExecHooks<EM, I, S> for AsanErrorsObserver {
fn pre_exec(&mut self, _state: &mut S, _mgr: &mut EM, _input: &I) -> Result<(), Error> {
unsafe { unsafe {
if ASAN_ERRORS.is_some() { if ASAN_ERRORS.is_some() {
ASAN_ERRORS.as_mut().unwrap().clear(); ASAN_ERRORS.as_mut().unwrap().clear();