new ondisk corpus

This commit is contained in:
Andrea Fioraldi 2021-02-22 15:19:35 +01:00
parent 3b0883721e
commit a5cc8313db
13 changed files with 260 additions and 223 deletions

View File

@ -5,10 +5,11 @@ use std::{env, path::PathBuf};
use libafl::{ use libafl::{
bolts::{shmem::UnixShMem, tuples::tuple_list}, bolts::{shmem::UnixShMem, tuples::tuple_list},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::setup_restarting_mgr, events::setup_restarting_mgr,
executors::{inprocess::InProcessExecutor, Executor, ExitKind}, executors::{inprocess::InProcessExecutor, Executor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::Input, inputs::Input,
mutators::scheduled::HavocBytesMutator, mutators::scheduled::HavocBytesMutator,
mutators::token_mutations::TokensMetadata, mutators::token_mutations::TokensMetadata,
@ -17,7 +18,7 @@ use libafl::{
state::{HasCorpus, HasMetadata, State}, state::{HasCorpus, HasMetadata, State},
stats::SimpleStats, stats::SimpleStats,
utils::{current_nanos, StdRand}, utils::{current_nanos, StdRand},
Error, Fuzzer, StdFuzzer, Error,
}; };
/// The name of the coverage map observer, to find it again in the observer list /// The name of the coverage map observer, to find it again in the observer list
@ -69,13 +70,12 @@ pub fn main() {
/// The actual fuzzer /// The actual fuzzer
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> { fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
let mut rand = StdRand::new(current_nanos());
// 'While the stats are state, they are usually used in the broker - which is likely never restarted // 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = SimpleStats::new(|s| println!("{}", s)); let stats = SimpleStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = let (state, mut restarting_mgr) =
setup_restarting_mgr::<_, _, _, _, _, _, UnixShMem, _>(stats, broker_port) setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port)
.expect("Failed to setup the restarter".into()); .expect("Failed to setup the restarter".into());
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
@ -86,6 +86,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// If not restarting, create a State from scratch // If not restarting, create a State from scratch
let mut state = state.unwrap_or(State::new( let mut state = state.unwrap_or(State::new(
StdRand::new(current_nanos()),
InMemoryCorpus::new(), InMemoryCorpus::new(),
tuple_list!(MaxMapFeedback::new_with_observer( tuple_list!(MaxMapFeedback::new_with_observer(
&NAME_COV_MAP, &NAME_COV_MAP,
@ -111,7 +112,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Setup a basic mutator with a mutational stage // Setup a basic mutator with a mutational stage
let mutator = HavocBytesMutator::default(); let mutator = HavocBytesMutator::default();
let stage = StdMutationalStage::new(mutator); let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); let fuzzer = StdFuzzer::new(RandCorpusScheduler::new(), tuple_list!(stage));
// Create the executor // Create the executor
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
@ -141,5 +142,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
println!("We imported {} inputs from disk.", state.corpus().count()); println!("We imported {} inputs from disk.", state.corpus().count());
} }
fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr) fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?;
Ok(())
} }

View File

@ -72,3 +72,15 @@ where
&mut self.current &mut self.current
} }
} }
impl<I> InMemoryCorpus<I>
where
I: Input,
{
pub fn new() -> Self {
Self {
entries: vec![],
current: None,
}
}
}

View File

@ -6,6 +6,11 @@ pub use testcase::Testcase;
pub mod inmemory; pub mod inmemory;
pub use inmemory::InMemoryCorpus; pub use inmemory::InMemoryCorpus;
#[cfg(feature = "std")]
pub mod ondisk;
#[cfg(feature = "std")]
pub use ondisk::OnDiskCorpus;
pub mod queue; pub mod queue;
pub use queue::QueueCorpusScheduler; pub use queue::QueueCorpusScheduler;
@ -110,4 +115,18 @@ where
} }
} }
impl<C, I, R, S> RandCorpusScheduler<C, I, R, S>
where
S: HasCorpus<C, I> + HasRand<R>,
C: Corpus<I>,
I: Input,
R: Rand,
{
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
pub type StdCorpusScheduler<C, I, R, S> = RandCorpusScheduler<C, I, R, S>; pub type StdCorpusScheduler<C, I, R, S> = RandCorpusScheduler<C, I, R, S>;

View File

@ -1,104 +1,104 @@
//! The ondisk corpus stores unused testcases to disk. //! The ondisk corpus stores unused testcases to disk.
use alloc::vec::Vec; use alloc::vec::Vec;
use core::{cell::RefCell, marker::PhantomData}; use core::cell::RefCell;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::path::PathBuf; use std::path::PathBuf;
use crate::{ use crate::{corpus::Corpus, corpus::Testcase, inputs::Input, Error};
corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::Input, utils::Rand, Error,
};
/// A corpus able to store testcases to disk, and load them from disk, when they are being used. /// A corpus able to store testcases to disk, and load them from disk, when they are being used.
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Default, Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct OnDiskCorpus<I, R> pub struct OnDiskCorpus<I>
where where
I: Input, I: Input,
R: Rand,
{ {
entries: Vec<RefCell<Testcase<I>>>, entries: Vec<RefCell<Testcase<I>>>,
current: Option<usize>,
dir_path: PathBuf, dir_path: PathBuf,
pos: usize,
phantom: PhantomData<R>,
} }
#[cfg(feature = "std")] impl<I> Corpus<I> for OnDiskCorpus<I>
impl<I, R> HasTestcaseVec<I> for OnDiskCorpus<I, R>
where where
I: Input, I: Input,
R: Rand,
{ {
/// Returns the number of elements
#[inline] #[inline]
fn entries(&self) -> &[RefCell<Testcase<I>>] { fn count(&self) -> usize {
&self.entries self.entries.len()
} }
#[inline]
fn entries_mut(&mut self) -> &mut Vec<RefCell<Testcase<I>>> {
&mut self.entries
}
}
#[cfg(feature = "std")] /// Add an entry to the corpus and return its index
impl<I, R> Corpus<I, R> for OnDiskCorpus<I, R> #[inline]
where fn add(&mut self, mut testcase: Testcase<I>) -> Result<usize, Error> {
I: Input, match testcase.filename() {
R: Rand,
{
/// Add an entry and save it to disk
fn add(&mut self, mut entry: Testcase<I>) -> usize {
match entry.filename() {
None => { None => {
// TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL) // TODO walk entry metadatas to ask for pices of filename (e.g. :havoc in AFL)
let filename = self.dir_path.join(format!("id_{}", &self.entries.len())); let filename = self.dir_path.join(format!("id_{}", &self.entries.len()));
let filename_str = filename.to_str().expect("Invalid Path"); let filename_str = filename.to_str().expect("Invalid Path");
entry.set_filename(filename_str.into()); testcase.set_filename(filename_str.into());
} }
_ => {} _ => {}
} }
entry testcase
.store_input() .store_input()
.expect("Could not save testcase to disk".into()); .expect("Could not save testcase to disk".into());
self.entries.push(RefCell::new(entry)); self.entries.push(RefCell::new(testcase));
self.entries.len() - 1 Ok(self.entries.len() - 1)
} }
/// Replaces the testcase at the given idx
#[inline] #[inline]
fn current_testcase(&self) -> (&RefCell<Testcase<I>>, usize) { fn replace(&mut self, idx: usize, testcase: Testcase<I>) -> Result<(), Error> {
(self.get(self.pos), self.pos) if idx >= self.entries.len() {
return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx)));
}
self.entries[idx] = RefCell::new(testcase);
Ok(())
} }
/// Gets the next entry /// Removes an entry from the corpus, returning it if it was present.
#[inline] #[inline]
fn next(&mut self, rand: &mut R) -> Result<(&RefCell<Testcase<I>>, usize), Error> { fn remove(&mut self, idx: usize) -> Result<Option<Testcase<I>>, Error> {
if self.count() == 0 { if idx >= self.entries.len() {
Err(Error::Empty("No entries in corpus".to_owned())) Ok(None)
} else { } else {
let len = { self.entries().len() }; Ok(Some(self.entries.remove(idx).into_inner()))
let id = rand.below(len as u64) as usize;
self.pos = id;
Ok((self.get(id), id))
} }
} }
// TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus /// Get by id
#[inline]
fn get(&self, idx: usize) -> Result<&RefCell<Testcase<I>>, Error> {
Ok(&self.entries[idx])
}
/// Current testcase scheduled
#[inline]
fn current(&self) -> &Option<usize> {
&self.current
}
/// Current testcase scheduled (mut)
#[inline]
fn current_mut(&mut self) -> &mut Option<usize> {
&mut self.current
}
} }
#[cfg(feature = "std")] impl<I> OnDiskCorpus<I>
impl<I, R> OnDiskCorpus<I, R>
where where
I: Input, I: Input,
R: Rand,
{ {
pub fn new(dir_path: PathBuf) -> Self { pub fn new(dir_path: PathBuf) -> Self {
Self { Self {
dir_path: dir_path,
entries: vec![], entries: vec![],
pos: 0, current: None,
phantom: PhantomData, dir_path: dir_path,
} }
} }
} }

View File

@ -46,6 +46,19 @@ where
} }
} }
impl<C, I, S> QueueCorpusScheduler<C, I, S>
where
S: HasCorpus<C, I>,
C: Corpus<I>,
I: Input,
{
pub fn new() -> Self {
Self {
phantom: PhantomData,
}
}
}
/* /*
#[cfg(test)] #[cfg(test)]
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -15,7 +15,6 @@ use crate::{
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasObjectives, HasSolutions}, state::{HasObjectives, HasSolutions},
utils::Rand,
Error, Error,
}; };
@ -124,7 +123,7 @@ where
/// * `name` - the name of this executor (to address it along the way) /// * `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
pub fn new<EM, OC, OFT, R, S>( pub fn new<EM, OC, OFT, S>(
name: &'static str, name: &'static str,
harness_fn: HarnessFunction<Self>, harness_fn: HarnessFunction<Self>,
observers: OT, observers: OT,
@ -136,12 +135,11 @@ where
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
R: Rand,
{ {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
setup_crash_handlers::<EM, I, OC, OFT, OT, R, S>(); setup_crash_handlers::<EM, I, OC, OFT, OT, S>();
} }
Self { Self {
@ -179,7 +177,6 @@ pub mod unix_signals {
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasObjectives, HasSolutions}, state::{HasObjectives, HasSolutions},
utils::Rand,
}; };
/// Let's get 8 mb for now. /// Let's get 8 mb for now.
const SIGNAL_STACK_SIZE: usize = 2 << 22; const SIGNAL_STACK_SIZE: usize = 2 << 22;
@ -195,18 +192,14 @@ pub mod unix_signals {
/// This is needed for certain non-rust side effects, as well as unix signal handling. /// This is needed for certain non-rust side effects, as well as unix signal handling.
static mut CURRENT_INPUT_PTR: *const c_void = ptr::null(); static mut CURRENT_INPUT_PTR: *const c_void = ptr::null();
unsafe fn inmem_handle_crash<EM, I, OC, OFT, OT, R, S>( unsafe fn inmem_handle_crash<EM, I, OC, OFT, OT, S>(_sig: c_int, info: siginfo_t, _void: c_void)
_sig: c_int, where
info: siginfo_t,
_void: c_void,
) where
EM: EventManager<I, S>, EM: EventManager<I, S>,
OT: ObserversTuple, OT: ObserversTuple,
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input, I: Input,
R: Rand,
{ {
if CURRENT_INPUT_PTR == ptr::null() { if CURRENT_INPUT_PTR == ptr::null() {
println!( println!(
@ -271,7 +264,7 @@ pub mod unix_signals {
std::process::exit(1); std::process::exit(1);
} }
unsafe fn inmem_handle_timeout<EM, I, OC, OFT, OT, R, S>( unsafe fn inmem_handle_timeout<EM, I, OC, OFT, OT, S>(
_sig: c_int, _sig: c_int,
_info: siginfo_t, _info: siginfo_t,
_void: c_void, _void: c_void,
@ -282,7 +275,6 @@ pub mod unix_signals {
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input, I: Input,
R: Rand,
{ {
dbg!("TIMEOUT/SIGUSR2 received"); dbg!("TIMEOUT/SIGUSR2 received");
if CURRENT_INPUT_PTR.is_null() { if CURRENT_INPUT_PTR.is_null() {
@ -350,7 +342,7 @@ pub mod unix_signals {
OBSERVERS_PTR = ptr::null(); OBSERVERS_PTR = ptr::null();
} }
pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, R, S>() pub unsafe fn setup_crash_handlers<EM, I, OC, OFT, OT, S>()
where where
EM: EventManager<I, S>, EM: EventManager<I, S>,
OT: ObserversTuple, OT: ObserversTuple,
@ -358,7 +350,6 @@ pub mod unix_signals {
OFT: FeedbacksTuple<I>, OFT: FeedbacksTuple<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
I: Input, I: Input,
R: Rand,
{ {
// First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`) // First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`)
if SIGNAL_STACK_PTR.is_null() { if SIGNAL_STACK_PTR.is_null() {
@ -375,7 +366,7 @@ pub mod unix_signals {
let mut sa: sigaction = mem::zeroed(); let mut sa: sigaction = mem::zeroed();
libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t);
sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
sa.sa_sigaction = inmem_handle_crash::<EM, I, OC, OFT, OT, R, S> as usize; sa.sa_sigaction = inmem_handle_crash::<EM, I, OC, OFT, OT, S> as usize;
for (sig, msg) in &[ for (sig, msg) in &[
(SIGSEGV, "segfault"), (SIGSEGV, "segfault"),
(SIGBUS, "sigbus"), (SIGBUS, "sigbus"),
@ -389,7 +380,7 @@ pub mod unix_signals {
} }
} }
sa.sa_sigaction = inmem_handle_timeout::<EM, I, OC, OFT, OT, R, S> as usize; sa.sa_sigaction = inmem_handle_timeout::<EM, I, OC, OFT, OT, S> as usize;
if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 { if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 {
panic!("Could not set up sigusr2 handler for timeouts"); panic!("Could not set up sigusr2 handler for timeouts");
} }

View File

@ -12,9 +12,12 @@ use crate::{
use core::marker::PhantomData; use core::marker::PhantomData;
/// Holds a set of stages /// Holds a set of stages
pub trait HasStages<ST, E, EM, S>: Sized pub trait HasStages<ST, E, EM, I, S>
where where
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input,
{ {
fn stages(&self) -> &ST; fn stages(&self) -> &ST;
@ -44,7 +47,9 @@ pub trait Fuzzer<E, EM, S> {
pub struct StdFuzzer<CS, ST, E, EM, I, OT, S> pub struct StdFuzzer<CS, ST, E, EM, I, OT, S>
where where
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input, I: Input,
{ {
scheduler: CS, scheduler: CS,
@ -52,10 +57,12 @@ where
phantom: PhantomData<(E, EM, I, OT, S)>, phantom: PhantomData<(E, EM, I, OT, S)>,
} }
impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, S> for StdFuzzer<CS, ST, E, EM, I, OT, S> impl<CS, ST, E, EM, I, OT, S> HasStages<ST, E, EM, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where where
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input, I: Input,
{ {
fn stages(&self) -> &ST { fn stages(&self) -> &ST {
@ -70,7 +77,9 @@ where
impl<CS, ST, E, EM, I, OT, S> HasCorpusScheduler<CS, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S> impl<CS, ST, E, EM, I, OT, S> HasCorpusScheduler<CS, I, S> for StdFuzzer<CS, ST, E, EM, I, OT, S>
where where
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input, I: Input,
{ {
fn scheduler(&self) -> &CS { fn scheduler(&self) -> &CS {
@ -86,7 +95,7 @@ impl<CS, ST, E, EM, I, OT, S> Fuzzer<E, EM, S> for StdFuzzer<CS, ST, E, EM, I, O
where where
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
S: HasExecutions, S: HasExecutions,
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
EM: EventManager<I, S>, EM: EventManager<I, S>,
E: Executor<I> + HasObservers<OT>, E: Executor<I> + HasObservers<OT>,
OT: ObserversTuple, OT: ObserversTuple,
@ -95,8 +104,7 @@ where
fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> { fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result<usize, Error> {
let idx = self.scheduler().next(state)?; let idx = self.scheduler().next(state)?;
self.stages() self.stages().perform_all(state, executor, manager, idx)?;
.perform_all(self, state, executor, manager, idx)?;
manager.process(state, executor)?; manager.process(state, executor)?;
Ok(idx) Ok(idx)
@ -125,7 +133,9 @@ where
impl<CS, ST, E, EM, I, OT, S> StdFuzzer<CS, ST, E, EM, I, OT, S> impl<CS, ST, E, EM, I, OT, S> StdFuzzer<CS, ST, E, EM, I, OT, S>
where where
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
ST: StagesTuple<E, EM, Self, S>, ST: StagesTuple<E, EM, I, S>,
E: Executor<I>,
EM: EventManager<I, S>,
I: Input, I: Input,
{ {
pub fn new(scheduler: CS, stages: ST) -> Self { pub fn new(scheduler: CS, stages: ST) -> Self {

View File

@ -14,18 +14,16 @@ use crate::{inputs::Input, Error};
/// A mutator takes input, and mutates it. /// A mutator takes input, and mutates it.
/// Simple as that. /// Simple as that.
pub trait Mutator<F, I, S> pub trait Mutator<I, S>
where where
I: Input, I: Input,
{ {
/// Mutate a given input /// Mutate a given input
fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32) fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error>;
-> Result<(), Error>;
/// Post-process given the outcome of the execution /// Post-process given the outcome of the execution
fn post_exec( fn post_exec(
&self, &self,
_fuzzer: &F,
_state: &mut S, _state: &mut S,
_is_interesting: u32, _is_interesting: u32,
_stage_idx: i32, _stage_idx: i32,

View File

@ -27,20 +27,20 @@ pub enum MutationResult {
// TODO maybe the mutator arg is not needed // TODO maybe the mutator arg is not needed
/// The generic function type that identifies mutations /// The generic function type that identifies mutations
pub type MutationFunction<F, I, M, S> = fn(&M, &F, &mut S, &mut I) -> Result<MutationResult, Error>; pub type MutationFunction<I, M, S> = fn(&M, &mut S, &mut I) -> Result<MutationResult, Error>;
pub trait ComposedByMutations<F, I, S> pub trait ComposedByMutations<I, S>
where where
I: Input, I: Input,
{ {
/// Get a mutation by index /// Get a mutation by index
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S>; fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S>;
/// Get the number of mutations /// Get the number of mutations
fn mutations_count(&self) -> usize; fn mutations_count(&self) -> usize;
/// Add a mutation /// Add a mutation
fn add_mutation(&mut self, mutation: MutationFunction<F, I, Self, S>); fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>);
} }
/// Mem move in the own vec /// Mem move in the own vec
@ -123,9 +123,9 @@ const INTERESTING_32: [i32; 27] = [
]; ];
/// Bitflip mutation for inputs with a bytes vector /// Bitflip mutation for inputs with a bytes vector
pub fn mutation_bitflip<F, I, M, R, S>( pub fn mutation_bitflip<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -146,9 +146,9 @@ where
} }
} }
pub fn mutation_byteflip<F, I, M, R, S>( pub fn mutation_byteflip<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -169,9 +169,9 @@ where
} }
} }
pub fn mutation_byteinc<F, I, M, R, S>( pub fn mutation_byteinc<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -193,9 +193,9 @@ where
} }
} }
pub fn mutation_bytedec<F, I, M, R, S>( pub fn mutation_bytedec<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -217,9 +217,9 @@ where
} }
} }
pub fn mutation_byteneg<F, I, M, R, S>( pub fn mutation_byteneg<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -240,9 +240,9 @@ where
} }
} }
pub fn mutation_byterand<F, I, M, R, S>( pub fn mutation_byterand<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -263,9 +263,9 @@ where
} }
} }
pub fn mutation_byteadd<F, I, M, R, S>( pub fn mutation_byteadd<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -291,9 +291,9 @@ where
} }
} }
pub fn mutation_wordadd<F, I, M, R, S>( pub fn mutation_wordadd<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -321,9 +321,9 @@ where
} }
} }
pub fn mutation_dwordadd<F, I, M, R, S>( pub fn mutation_dwordadd<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -351,9 +351,9 @@ where
} }
} }
pub fn mutation_qwordadd<F, I, M, R, S>( pub fn mutation_qwordadd<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -381,9 +381,9 @@ where
} }
} }
pub fn mutation_byteinteresting<F, I, M, R, S>( pub fn mutation_byteinteresting<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -405,9 +405,9 @@ where
} }
} }
pub fn mutation_wordinteresting<F, I, M, R, S>( pub fn mutation_wordinteresting<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -435,9 +435,9 @@ where
} }
} }
pub fn mutation_dwordinteresting<F, I, M, R, S>( pub fn mutation_dwordinteresting<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -465,9 +465,9 @@ where
} }
} }
pub fn mutation_bytesdelete<F, I, M, R, S>( pub fn mutation_bytesdelete<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -488,9 +488,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesexpand<F, I, M, R, S>( pub fn mutation_bytesexpand<I, M, R, S>(
mutator: &M, mutator: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -518,9 +518,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesinsert<F, I, M, R, S>( pub fn mutation_bytesinsert<I, M, R, S>(
mutator: &M, mutator: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -551,9 +551,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesrandinsert<F, I, M, R, S>( pub fn mutation_bytesrandinsert<I, M, R, S>(
mutator: &M, mutator: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -584,9 +584,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesset<F, I, M, R, S>( pub fn mutation_bytesset<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -609,9 +609,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesrandset<F, I, M, R, S>( pub fn mutation_bytesrandset<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -634,9 +634,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytescopy<F, I, M, R, S>( pub fn mutation_bytescopy<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -659,9 +659,9 @@ where
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
pub fn mutation_bytesswap<F, I, M, R, S>( pub fn mutation_bytesswap<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -687,9 +687,9 @@ where
} }
/// Crossover insert mutation /// Crossover insert mutation
pub fn mutation_crossover_insert<C, F, I, M, R, S>( pub fn mutation_crossover_insert<C, I, M, R, S>(
mutator: &M, mutator: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -745,9 +745,9 @@ where
} }
/// Crossover replace mutation /// Crossover replace mutation
pub fn mutation_crossover_replace<C, F, I, M, R, S>( pub fn mutation_crossover_replace<C, I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -808,9 +808,9 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
} }
/// Splicing mutation from AFL /// Splicing mutation from AFL
pub fn mutation_splice<C, F, I, M, R, S>( pub fn mutation_splice<C, I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>

View File

@ -15,7 +15,7 @@ use crate::{
pub use crate::mutators::mutations::*; pub use crate::mutators::mutations::*;
pub use crate::mutators::token_mutations::*; pub use crate::mutators::token_mutations::*;
pub trait ScheduledMutator<F, I, S>: Mutator<F, I, S> + ComposedByMutations<F, I, S> pub trait ScheduledMutator<I, S>: Mutator<I, S> + ComposedByMutations<I, S>
where where
I: Input, I: Input,
{ {
@ -27,34 +27,28 @@ where
/// New default implementation for mutate /// New default implementation for mutate
/// Implementations must forward mutate() to this method /// Implementations must forward mutate() to this method
fn scheduled_mutate( fn scheduled_mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> {
&self,
fuzzer: &F,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<(), Error> {
let num = self.iterations(state, input); let num = self.iterations(state, input);
for _ in 0..num { for _ in 0..num {
let idx = self.schedule(self.mutations_count(), state, input); let idx = self.schedule(self.mutations_count(), state, input);
self.mutation_by_idx(idx)(self, fuzzer, state, input)?; self.mutation_by_idx(idx)(self, state, input)?;
} }
Ok(()) Ok(())
} }
} }
pub struct StdScheduledMutator<F, I, R, S> pub struct StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
mutations: Vec<MutationFunction<F, I, Self, S>>, mutations: Vec<MutationFunction<I, Self, S>>,
max_size: usize, max_size: usize,
phantom: PhantomData<R>, phantom: PhantomData<R>,
} }
impl<F, I, R, S> Debug for StdScheduledMutator<F, I, R, S> impl<I, R, S> Debug for StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
@ -71,31 +65,25 @@ where
} }
} }
impl<F, I, R, S> Mutator<F, I, S> for StdScheduledMutator<F, I, R, S> impl<I, R, S> Mutator<I, S> for StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
fn mutate( fn mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> {
&self, self.scheduled_mutate(state, input, _stage_idx)
fuzzer: &F,
state: &mut S,
input: &mut I,
_stage_idx: i32,
) -> Result<(), Error> {
self.scheduled_mutate(fuzzer, state, input, _stage_idx)
} }
} }
impl<F, I, R, S> ComposedByMutations<F, I, S> for StdScheduledMutator<F, I, R, S> impl<I, R, S> ComposedByMutations<I, S> for StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
R: Rand, R: Rand,
{ {
#[inline] #[inline]
fn mutation_by_idx(&self, index: usize) -> MutationFunction<F, I, Self, S> { fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S> {
self.mutations[index] self.mutations[index]
} }
@ -105,12 +93,12 @@ where
} }
#[inline] #[inline]
fn add_mutation(&mut self, mutation: MutationFunction<F, I, Self, S>) { fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>) {
self.mutations.push(mutation) self.mutations.push(mutation)
} }
} }
impl<F, I, R, S> ScheduledMutator<F, I, S> for StdScheduledMutator<F, I, R, S> impl<I, R, S> ScheduledMutator<I, S> for StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
@ -128,7 +116,7 @@ where
} }
} }
impl<F, I, R, S> HasMaxSize for StdScheduledMutator<F, I, R, S> impl<I, R, S> HasMaxSize for StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
@ -145,7 +133,7 @@ where
} }
} }
impl<F, I, R, S> StdScheduledMutator<F, I, R, S> impl<I, R, S> StdScheduledMutator<I, R, S>
where where
I: Input, I: Input,
S: HasRand<R>, S: HasRand<R>,
@ -161,7 +149,7 @@ where
} }
/// Create a new StdScheduledMutator instance specifying mutations /// Create a new StdScheduledMutator instance specifying mutations
pub fn with_mutations(mutations: Vec<MutationFunction<F, I, Self, S>>) -> Self { pub fn with_mutations(mutations: Vec<MutationFunction<I, Self, S>>) -> Self {
StdScheduledMutator { StdScheduledMutator {
mutations: mutations, mutations: mutations,
max_size: DEFAULT_MAX_SIZE, max_size: DEFAULT_MAX_SIZE,
@ -172,35 +160,29 @@ where
/// Schedule some selected byte level mutations given a ScheduledMutator type /// Schedule some selected byte level mutations given a ScheduledMutator type
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct HavocBytesMutator<C, F, I, R, S, SM> pub struct HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<F, I, S> + HasMaxSize, SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {
scheduled: SM, scheduled: SM,
phantom: PhantomData<(C, F, I, R, S)>, phantom: PhantomData<(C, I, R, S)>,
} }
impl<C, F, I, R, S, SM> Mutator<F, I, S> for HavocBytesMutator<C, F, I, R, S, SM> impl<C, I, R, S, SM> Mutator<I, S> for HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<F, I, S> + HasMaxSize, SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>, C: Corpus<I>,
R: Rand, R: Rand,
{ {
/// Mutate bytes /// Mutate bytes
fn mutate( fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error> {
&self, self.scheduled.mutate(state, input, stage_idx)?;
fuzzer: &F,
state: &mut S,
input: &mut I,
stage_idx: i32,
) -> Result<(), Error> {
self.scheduled.mutate(fuzzer, state, input, stage_idx)?;
/*let num = self.scheduled.iterations(state, input); /*let num = self.scheduled.iterations(state, input);
for _ in 0..num { for _ in 0..num {
let idx = self.scheduled.schedule(14, state, input); let idx = self.scheduled.schedule(14, state, input);
@ -226,9 +208,9 @@ where
} }
} }
impl<C, F, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, F, I, R, S, SM> impl<C, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<F, I, S> + HasMaxSize, SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>, C: Corpus<I>,
@ -245,9 +227,9 @@ where
} }
} }
impl<C, F, I, R, S, SM> HavocBytesMutator<C, F, I, R, S, SM> impl<C, I, R, S, SM> HavocBytesMutator<C, I, R, S, SM>
where where
SM: ScheduledMutator<F, I, S> + HasMaxSize, SM: ScheduledMutator<I, S> + HasMaxSize,
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
C: Corpus<I>, C: Corpus<I>,
@ -264,7 +246,7 @@ where
} }
} }
impl<C, F, I, R, S> Default for HavocBytesMutator<C, F, I, R, S, StdScheduledMutator<F, I, R, S>> impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>>
where where
I: Input + HasBytesVec, I: Input + HasBytesVec,
S: HasRand<R> + HasCorpus<C, I> + HasMetadata, S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
@ -273,7 +255,7 @@ where
{ {
/// Create a new HavocBytesMutator instance wrapping StdScheduledMutator /// Create a new HavocBytesMutator instance wrapping StdScheduledMutator
fn default() -> Self { fn default() -> Self {
let mut scheduled = StdScheduledMutator::<F, I, R, S>::new(); let mut scheduled = StdScheduledMutator::<I, R, S>::new();
scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_bitflip);
scheduled.add_mutation(mutation_byteflip); scheduled.add_mutation(mutation_byteflip);
scheduled.add_mutation(mutation_byteinc); scheduled.add_mutation(mutation_byteinc);

View File

@ -30,9 +30,8 @@ impl TokensMetadata {
} }
/// Insert a dictionary token /// Insert a dictionary token
pub fn mutation_tokeninsert<F, I, M, R, S>( pub fn mutation_tokeninsert<I, M, R, S>(
mutator: &M, mutator: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>
@ -77,9 +76,8 @@ where
} }
/// Overwrite with a dictionary token /// Overwrite with a dictionary token
pub fn mutation_tokenreplace<F, I, M, R, S>( pub fn mutation_tokenreplace<I, M, R, S>(
_: &M, _: &M,
_: &F,
state: &mut S, state: &mut S,
input: &mut I, input: &mut I,
) -> Result<MutationResult, Error> ) -> Result<MutationResult, Error>

View File

@ -1,15 +1,21 @@
pub mod mutational; pub mod mutational;
pub use mutational::StdMutationalStage; pub use mutational::StdMutationalStage;
use crate::{bolts::tuples::TupleList, Error}; use crate::{
bolts::tuples::TupleList, events::EventManager, executors::Executor, inputs::Input, Error,
};
/// A stage is one step in the fuzzing process. /// A stage is one step in the fuzzing process.
/// Multiple stages will be scheduled one by one for each input. /// Multiple stages will be scheduled one by one for each input.
pub trait Stage<E, EM, F, S> { pub trait Stage<E, EM, I, S>
where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
/// Run the stage /// Run the stage
fn perform( fn perform(
&self, &self,
fuzzer: &F,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
@ -17,10 +23,14 @@ pub trait Stage<E, EM, F, S> {
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
pub trait StagesTuple<E, EM, F, S> { pub trait StagesTuple<E, EM, I, S>
where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
fn perform_all( fn perform_all(
&self, &self,
fuzzer: &F,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
@ -28,28 +38,33 @@ pub trait StagesTuple<E, EM, F, S> {
) -> Result<(), Error>; ) -> Result<(), Error>;
} }
impl<E, EM, F, S> StagesTuple<E, EM, F, S> for () { impl<E, EM, I, S> StagesTuple<E, EM, I, S> for ()
fn perform_all(&self, _: &F, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> { where
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{
fn perform_all(&self, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }
impl<Head, Tail, E, EM, F, S> StagesTuple<E, EM, F, S> for (Head, Tail) impl<Head, Tail, E, EM, I, S> StagesTuple<E, EM, I, S> for (Head, Tail)
where where
Head: Stage<E, EM, F, S>, Head: Stage<E, EM, I, S>,
Tail: StagesTuple<E, EM, F, S> + TupleList, Tail: StagesTuple<E, EM, I, S> + TupleList,
EM: EventManager<I, S>,
E: Executor<I>,
I: Input,
{ {
fn perform_all( fn perform_all(
&self, &self,
fuzzer: &F,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.0 self.0.perform(state, executor, manager, corpus_idx)?;
.perform(fuzzer, state, executor, manager, corpus_idx)?; self.1.perform_all(state, executor, manager, corpus_idx)
self.1
.perform_all(fuzzer, state, executor, manager, corpus_idx)
} }
} }

View File

@ -18,9 +18,9 @@ use crate::{
/// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// A Mutational stage is the stage in a fuzzing run that mutates inputs.
/// Mutational stages will usually have a range of mutations that are /// Mutational stages will usually have a range of mutations that are
/// being applied to the input one by one, between executions. /// being applied to the input one by one, between executions.
pub trait MutationalStage<C, E, EM, F, I, M, OT, S>: Stage<E, EM, F, S> pub trait MutationalStage<C, E, EM, I, M, OT, S>: Stage<E, EM, I, S>
where where
M: Mutator<F, I, S>, M: Mutator<I, S>,
I: Input, I: Input,
S: HasCorpus<C, I> + Evaluator<I>, S: HasCorpus<C, I> + Evaluator<I>,
C: Corpus<I>, C: Corpus<I>,
@ -40,7 +40,6 @@ where
/// Runs this (mutational) stage for the given testcase /// Runs this (mutational) stage for the given testcase
fn perform_mutational( fn perform_mutational(
&self, &self,
fuzzer: &F,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
@ -54,12 +53,11 @@ where
.borrow_mut() .borrow_mut()
.load_input()? .load_input()?
.clone(); .clone();
self.mutator() self.mutator().mutate(state, &mut input_mut, i as i32)?;
.mutate(fuzzer, state, &mut input_mut, i as i32)?;
let fitness = state.evaluate_input(input_mut, executor, manager)?; let fitness = state.evaluate_input(input_mut, executor, manager)?;
self.mutator().post_exec(fuzzer, state, fitness, i as i32)?; self.mutator().post_exec(state, fitness, i as i32)?;
} }
Ok(()) Ok(())
} }
@ -69,9 +67,9 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
/// The default mutational stage /// The default mutational stage
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct StdMutationalStage<C, E, EM, F, I, M, OT, R, S> pub struct StdMutationalStage<C, E, EM, I, M, OT, R, S>
where where
M: Mutator<F, I, S>, M: Mutator<I, S>,
I: Input, I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
@ -81,13 +79,13 @@ where
R: Rand, R: Rand,
{ {
mutator: M, mutator: M,
phantom: PhantomData<(C, E, EM, F, I, OT, R, S)>, phantom: PhantomData<(C, E, EM, I, OT, R, S)>,
} }
impl<C, E, EM, F, I, M, OT, R, S> MutationalStage<C, E, EM, F, I, M, OT, S> impl<C, E, EM, I, M, OT, R, S> MutationalStage<C, E, EM, I, M, OT, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S> for StdMutationalStage<C, E, EM, I, M, OT, R, S>
where where
M: Mutator<F, I, S>, M: Mutator<I, S>,
I: Input, I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
@ -114,10 +112,9 @@ where
} }
} }
impl<C, E, EM, F, I, M, OT, R, S> Stage<E, EM, F, S> impl<C, E, EM, I, M, OT, R, S> Stage<E, EM, I, S> for StdMutationalStage<C, E, EM, I, M, OT, R, S>
for StdMutationalStage<C, E, EM, F, I, M, OT, R, S>
where where
M: Mutator<F, I, S>, M: Mutator<I, S>,
I: Input, I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,
@ -129,19 +126,18 @@ where
#[inline] #[inline]
fn perform( fn perform(
&self, &self,
fuzzer: &F,
state: &mut S, state: &mut S,
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
) -> Result<(), Error> { ) -> Result<(), Error> {
self.perform_mutational(fuzzer, state, executor, manager, corpus_idx) self.perform_mutational(state, executor, manager, corpus_idx)
} }
} }
impl<C, E, EM, F, I, M, OT, R, S> StdMutationalStage<C, E, EM, F, I, M, OT, R, S> impl<C, E, EM, I, M, OT, R, S> StdMutationalStage<C, E, EM, I, M, OT, R, S>
where where
M: Mutator<F, I, S>, M: Mutator<I, S>,
I: Input, I: Input,
S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>, S: HasCorpus<C, I> + Evaluator<I> + HasRand<R>,
C: Corpus<I>, C: Corpus<I>,