diff --git a/fuzzers/libfuzzer_libpng/src/mod.rs b/fuzzers/libfuzzer_libpng/src/mod.rs index 50a02df796..66097da495 100644 --- a/fuzzers/libfuzzer_libpng/src/mod.rs +++ b/fuzzers/libfuzzer_libpng/src/mod.rs @@ -5,10 +5,11 @@ use std::{env, path::PathBuf}; use libafl::{ bolts::{shmem::UnixShMem, tuples::tuple_list}, - corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, + corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler}, events::setup_restarting_mgr, executors::{inprocess::InProcessExecutor, Executor, ExitKind}, feedbacks::{CrashFeedback, MaxMapFeedback}, + fuzzer::{Fuzzer, StdFuzzer}, inputs::Input, mutators::scheduled::HavocBytesMutator, mutators::token_mutations::TokensMetadata, @@ -17,7 +18,7 @@ use libafl::{ state::{HasCorpus, HasMetadata, State}, stats::SimpleStats, utils::{current_nanos, StdRand}, - Error, Fuzzer, StdFuzzer, + Error, }; /// 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 fn fuzz(corpus_dirs: Vec, 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 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. 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()); // Create an observation channel using the coverage map @@ -86,6 +86,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // If not restarting, create a State from scratch let mut state = state.unwrap_or(State::new( + StdRand::new(current_nanos()), InMemoryCorpus::new(), tuple_list!(MaxMapFeedback::new_with_observer( &NAME_COV_MAP, @@ -111,7 +112,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Setup a basic mutator with a mutational stage let mutator = HavocBytesMutator::default(); 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 let mut executor = InProcessExecutor::new( @@ -141,5 +142,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> 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(()) } diff --git a/libafl/src/corpus/inmemory.rs b/libafl/src/corpus/inmemory.rs index 22a28ff67a..72ede51924 100644 --- a/libafl/src/corpus/inmemory.rs +++ b/libafl/src/corpus/inmemory.rs @@ -72,3 +72,15 @@ where &mut self.current } } + +impl InMemoryCorpus +where + I: Input, +{ + pub fn new() -> Self { + Self { + entries: vec![], + current: None, + } + } +} diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 6ed7f18bb1..cd194bcfdb 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -6,6 +6,11 @@ pub use testcase::Testcase; pub mod inmemory; pub use inmemory::InMemoryCorpus; +#[cfg(feature = "std")] +pub mod ondisk; +#[cfg(feature = "std")] +pub use ondisk::OnDiskCorpus; + pub mod queue; pub use queue::QueueCorpusScheduler; @@ -110,4 +115,18 @@ where } } +impl RandCorpusScheduler +where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand, +{ + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + pub type StdCorpusScheduler = RandCorpusScheduler; diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 00dd84e852..d4d8706f92 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -1,104 +1,104 @@ //! The ondisk corpus stores unused testcases to disk. use alloc::vec::Vec; -use core::{cell::RefCell, marker::PhantomData}; +use core::cell::RefCell; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use std::path::PathBuf; -use crate::{ - corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::Input, utils::Rand, Error, -}; +use crate::{corpus::Corpus, corpus::Testcase, inputs::Input, Error}; /// A corpus able to store testcases to disk, and load them from disk, when they are being used. #[cfg(feature = "std")] -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Default, Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] -pub struct OnDiskCorpus +pub struct OnDiskCorpus where I: Input, - R: Rand, { entries: Vec>>, + current: Option, dir_path: PathBuf, - pos: usize, - phantom: PhantomData, } -#[cfg(feature = "std")] -impl HasTestcaseVec for OnDiskCorpus +impl Corpus for OnDiskCorpus where I: Input, - R: Rand, { + /// Returns the number of elements #[inline] - fn entries(&self) -> &[RefCell>] { - &self.entries + fn count(&self) -> usize { + self.entries.len() } - #[inline] - fn entries_mut(&mut self) -> &mut Vec>> { - &mut self.entries - } -} -#[cfg(feature = "std")] -impl Corpus for OnDiskCorpus -where - I: Input, - R: Rand, -{ - /// Add an entry and save it to disk - fn add(&mut self, mut entry: Testcase) -> usize { - match entry.filename() { + /// Add an entry to the corpus and return its index + #[inline] + fn add(&mut self, mut testcase: Testcase) -> Result { + match testcase.filename() { None => { // 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_str = filename.to_str().expect("Invalid Path"); - entry.set_filename(filename_str.into()); + testcase.set_filename(filename_str.into()); } _ => {} } - entry + testcase .store_input() .expect("Could not save testcase to disk".into()); - self.entries.push(RefCell::new(entry)); - self.entries.len() - 1 + self.entries.push(RefCell::new(testcase)); + Ok(self.entries.len() - 1) } + /// Replaces the testcase at the given idx #[inline] - fn current_testcase(&self) -> (&RefCell>, usize) { - (self.get(self.pos), self.pos) + fn replace(&mut self, idx: usize, testcase: Testcase) -> Result<(), Error> { + 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] - fn next(&mut self, rand: &mut R) -> Result<(&RefCell>, usize), Error> { - if self.count() == 0 { - Err(Error::Empty("No entries in corpus".to_owned())) + fn remove(&mut self, idx: usize) -> Result>, Error> { + if idx >= self.entries.len() { + Ok(None) } else { - let len = { self.entries().len() }; - let id = rand.below(len as u64) as usize; - self.pos = id; - Ok((self.get(id), id)) + Ok(Some(self.entries.remove(idx).into_inner())) } } - // TODO save and remove files, cache, etc..., ATM use just InMemoryCorpus + /// Get by id + #[inline] + fn get(&self, idx: usize) -> Result<&RefCell>, Error> { + Ok(&self.entries[idx]) + } + + /// Current testcase scheduled + #[inline] + fn current(&self) -> &Option { + &self.current + } + + /// Current testcase scheduled (mut) + #[inline] + fn current_mut(&mut self) -> &mut Option { + &mut self.current + } } -#[cfg(feature = "std")] -impl OnDiskCorpus +impl OnDiskCorpus where I: Input, - R: Rand, { pub fn new(dir_path: PathBuf) -> Self { Self { - dir_path: dir_path, entries: vec![], - pos: 0, - phantom: PhantomData, + current: None, + dir_path: dir_path, } } } diff --git a/libafl/src/corpus/queue.rs b/libafl/src/corpus/queue.rs index 12fa682e14..2d7abdf3b2 100644 --- a/libafl/src/corpus/queue.rs +++ b/libafl/src/corpus/queue.rs @@ -46,6 +46,19 @@ where } } +impl QueueCorpusScheduler +where + S: HasCorpus, + C: Corpus, + I: Input, +{ + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + /* #[cfg(test)] #[cfg(feature = "std")] diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 65222ab004..feb4bc5a37 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -15,7 +15,6 @@ use crate::{ inputs::{HasTargetBytes, Input}, observers::ObserversTuple, state::{HasObjectives, HasSolutions}, - utils::Rand, Error, }; @@ -124,7 +123,7 @@ where /// * `name` - the name of this executor (to address it along the way) /// * `harness_fn` - the harness, executiong the function /// * `observers` - the observers observing the target during execution - pub fn new( + pub fn new( name: &'static str, harness_fn: HarnessFunction, observers: OT, @@ -136,12 +135,11 @@ where OC: Corpus, OFT: FeedbacksTuple, S: HasObjectives + HasSolutions, - R: Rand, { #[cfg(feature = "std")] #[cfg(unix)] unsafe { - setup_crash_handlers::(); + setup_crash_handlers::(); } Self { @@ -179,7 +177,6 @@ pub mod unix_signals { inputs::Input, observers::ObserversTuple, state::{HasObjectives, HasSolutions}, - utils::Rand, }; /// Let's get 8 mb for now. 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. static mut CURRENT_INPUT_PTR: *const c_void = ptr::null(); - unsafe fn inmem_handle_crash( - _sig: c_int, - info: siginfo_t, - _void: c_void, - ) where + unsafe fn inmem_handle_crash(_sig: c_int, info: siginfo_t, _void: c_void) + where EM: EventManager, OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, S: HasObjectives + HasSolutions, I: Input, - R: Rand, { if CURRENT_INPUT_PTR == ptr::null() { println!( @@ -271,7 +264,7 @@ pub mod unix_signals { std::process::exit(1); } - unsafe fn inmem_handle_timeout( + unsafe fn inmem_handle_timeout( _sig: c_int, _info: siginfo_t, _void: c_void, @@ -282,7 +275,6 @@ pub mod unix_signals { OFT: FeedbacksTuple, S: HasObjectives + HasSolutions, I: Input, - R: Rand, { dbg!("TIMEOUT/SIGUSR2 received"); if CURRENT_INPUT_PTR.is_null() { @@ -350,7 +342,7 @@ pub mod unix_signals { OBSERVERS_PTR = ptr::null(); } - pub unsafe fn setup_crash_handlers() + pub unsafe fn setup_crash_handlers() where EM: EventManager, OT: ObserversTuple, @@ -358,7 +350,6 @@ pub mod unix_signals { OFT: FeedbacksTuple, S: HasObjectives + HasSolutions, I: Input, - R: Rand, { // First, set up our own stack to be used during segfault handling. (and specify `SA_ONSTACK` in `sigaction`) if SIGNAL_STACK_PTR.is_null() { @@ -375,7 +366,7 @@ pub mod unix_signals { let mut sa: sigaction = mem::zeroed(); libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; - sa.sa_sigaction = inmem_handle_crash:: as usize; + sa.sa_sigaction = inmem_handle_crash:: as usize; for (sig, msg) in &[ (SIGSEGV, "segfault"), (SIGBUS, "sigbus"), @@ -389,7 +380,7 @@ pub mod unix_signals { } } - sa.sa_sigaction = inmem_handle_timeout:: as usize; + sa.sa_sigaction = inmem_handle_timeout:: as usize; if sigaction(SIGUSR2, &mut sa as *mut sigaction, ptr::null_mut()) < 0 { panic!("Could not set up sigusr2 handler for timeouts"); } diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index 37c986a26c..da4b20e3f3 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -12,9 +12,12 @@ use crate::{ use core::marker::PhantomData; /// Holds a set of stages -pub trait HasStages: Sized +pub trait HasStages where - ST: StagesTuple, + ST: StagesTuple, + E: Executor, + EM: EventManager, + I: Input, { fn stages(&self) -> &ST; @@ -44,7 +47,9 @@ pub trait Fuzzer { pub struct StdFuzzer where CS: CorpusScheduler, - ST: StagesTuple, + ST: StagesTuple, + E: Executor, + EM: EventManager, I: Input, { scheduler: CS, @@ -52,10 +57,12 @@ where phantom: PhantomData<(E, EM, I, OT, S)>, } -impl HasStages for StdFuzzer +impl HasStages for StdFuzzer where CS: CorpusScheduler, - ST: StagesTuple, + ST: StagesTuple, + E: Executor, + EM: EventManager, I: Input, { fn stages(&self) -> &ST { @@ -70,7 +77,9 @@ where impl HasCorpusScheduler for StdFuzzer where CS: CorpusScheduler, - ST: StagesTuple, + ST: StagesTuple, + E: Executor, + EM: EventManager, I: Input, { fn scheduler(&self) -> &CS { @@ -86,7 +95,7 @@ impl Fuzzer for StdFuzzer, S: HasExecutions, - ST: StagesTuple, + ST: StagesTuple, EM: EventManager, E: Executor + HasObservers, OT: ObserversTuple, @@ -95,8 +104,7 @@ where fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result { let idx = self.scheduler().next(state)?; - self.stages() - .perform_all(self, state, executor, manager, idx)?; + self.stages().perform_all(state, executor, manager, idx)?; manager.process(state, executor)?; Ok(idx) @@ -125,7 +133,9 @@ where impl StdFuzzer where CS: CorpusScheduler, - ST: StagesTuple, + ST: StagesTuple, + E: Executor, + EM: EventManager, I: Input, { pub fn new(scheduler: CS, stages: ST) -> Self { diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 73c5203663..2337152477 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -14,18 +14,16 @@ use crate::{inputs::Input, Error}; /// A mutator takes input, and mutates it. /// Simple as that. -pub trait Mutator +pub trait Mutator where I: Input, { /// Mutate a given input - fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32) - -> Result<(), Error>; + fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error>; /// Post-process given the outcome of the execution fn post_exec( &self, - _fuzzer: &F, _state: &mut S, _is_interesting: u32, _stage_idx: i32, diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 730efad2a1..4b394e65a6 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -27,20 +27,20 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = fn(&M, &F, &mut S, &mut I) -> Result; +pub type MutationFunction = fn(&M, &mut S, &mut I) -> Result; -pub trait ComposedByMutations +pub trait ComposedByMutations where I: Input, { /// Get a mutation by index - fn mutation_by_idx(&self, index: usize) -> MutationFunction; + fn mutation_by_idx(&self, index: usize) -> MutationFunction; /// Get the number of mutations fn mutations_count(&self) -> usize; /// Add a mutation - fn add_mutation(&mut self, mutation: MutationFunction); + fn add_mutation(&mut self, mutation: MutationFunction); } /// Mem move in the own vec @@ -123,9 +123,9 @@ const INTERESTING_32: [i32; 27] = [ ]; /// Bitflip mutation for inputs with a bytes vector -pub fn mutation_bitflip( +pub fn mutation_bitflip( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -146,9 +146,9 @@ where } } -pub fn mutation_byteflip( +pub fn mutation_byteflip( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -169,9 +169,9 @@ where } } -pub fn mutation_byteinc( +pub fn mutation_byteinc( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -193,9 +193,9 @@ where } } -pub fn mutation_bytedec( +pub fn mutation_bytedec( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -217,9 +217,9 @@ where } } -pub fn mutation_byteneg( +pub fn mutation_byteneg( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -240,9 +240,9 @@ where } } -pub fn mutation_byterand( +pub fn mutation_byterand( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -263,9 +263,9 @@ where } } -pub fn mutation_byteadd( +pub fn mutation_byteadd( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -291,9 +291,9 @@ where } } -pub fn mutation_wordadd( +pub fn mutation_wordadd( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -321,9 +321,9 @@ where } } -pub fn mutation_dwordadd( +pub fn mutation_dwordadd( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -351,9 +351,9 @@ where } } -pub fn mutation_qwordadd( +pub fn mutation_qwordadd( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -381,9 +381,9 @@ where } } -pub fn mutation_byteinteresting( +pub fn mutation_byteinteresting( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -405,9 +405,9 @@ where } } -pub fn mutation_wordinteresting( +pub fn mutation_wordinteresting( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -435,9 +435,9 @@ where } } -pub fn mutation_dwordinteresting( +pub fn mutation_dwordinteresting( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -465,9 +465,9 @@ where } } -pub fn mutation_bytesdelete( +pub fn mutation_bytesdelete( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -488,9 +488,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesexpand( +pub fn mutation_bytesexpand( mutator: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -518,9 +518,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesinsert( +pub fn mutation_bytesinsert( mutator: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -551,9 +551,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandinsert( +pub fn mutation_bytesrandinsert( mutator: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -584,9 +584,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesset( +pub fn mutation_bytesset( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -609,9 +609,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandset( +pub fn mutation_bytesrandset( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -634,9 +634,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytescopy( +pub fn mutation_bytescopy( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -659,9 +659,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesswap( +pub fn mutation_bytesswap( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -687,9 +687,9 @@ where } /// Crossover insert mutation -pub fn mutation_crossover_insert( +pub fn mutation_crossover_insert( mutator: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -745,9 +745,9 @@ where } /// Crossover replace mutation -pub fn mutation_crossover_replace( +pub fn mutation_crossover_replace( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result @@ -808,9 +808,9 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { } /// Splicing mutation from AFL -pub fn mutation_splice( +pub fn mutation_splice( _: &M, - _: &F, + state: &mut S, input: &mut I, ) -> Result diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 2a3feeb1f7..7192eedfb8 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -15,7 +15,7 @@ use crate::{ pub use crate::mutators::mutations::*; pub use crate::mutators::token_mutations::*; -pub trait ScheduledMutator: Mutator + ComposedByMutations +pub trait ScheduledMutator: Mutator + ComposedByMutations where I: Input, { @@ -27,34 +27,28 @@ where /// New default implementation for mutate /// Implementations must forward mutate() to this method - fn scheduled_mutate( - &self, - fuzzer: &F, - state: &mut S, - input: &mut I, - _stage_idx: i32, - ) -> Result<(), Error> { + fn scheduled_mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> { let num = self.iterations(state, input); for _ in 0..num { 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(()) } } -pub struct StdScheduledMutator +pub struct StdScheduledMutator where I: Input, S: HasRand, R: Rand, { - mutations: Vec>, + mutations: Vec>, max_size: usize, phantom: PhantomData, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where I: Input, S: HasRand, @@ -71,31 +65,25 @@ where } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where I: Input, S: HasRand, R: Rand, { - fn mutate( - &self, - fuzzer: &F, - state: &mut S, - input: &mut I, - _stage_idx: i32, - ) -> Result<(), Error> { - self.scheduled_mutate(fuzzer, state, input, _stage_idx) + fn mutate(&self, state: &mut S, input: &mut I, _stage_idx: i32) -> Result<(), Error> { + self.scheduled_mutate(state, input, _stage_idx) } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where I: Input, S: HasRand, R: Rand, { #[inline] - fn mutation_by_idx(&self, index: usize) -> MutationFunction { + fn mutation_by_idx(&self, index: usize) -> MutationFunction { self.mutations[index] } @@ -105,12 +93,12 @@ where } #[inline] - fn add_mutation(&mut self, mutation: MutationFunction) { + fn add_mutation(&mut self, mutation: MutationFunction) { self.mutations.push(mutation) } } -impl ScheduledMutator for StdScheduledMutator +impl ScheduledMutator for StdScheduledMutator where I: Input, S: HasRand, @@ -128,7 +116,7 @@ where } } -impl HasMaxSize for StdScheduledMutator +impl HasMaxSize for StdScheduledMutator where I: Input, S: HasRand, @@ -145,7 +133,7 @@ where } } -impl StdScheduledMutator +impl StdScheduledMutator where I: Input, S: HasRand, @@ -161,7 +149,7 @@ where } /// Create a new StdScheduledMutator instance specifying mutations - pub fn with_mutations(mutations: Vec>) -> Self { + pub fn with_mutations(mutations: Vec>) -> Self { StdScheduledMutator { mutations: mutations, max_size: DEFAULT_MAX_SIZE, @@ -172,35 +160,29 @@ where /// Schedule some selected byte level mutations given a ScheduledMutator type #[derive(Clone, Debug)] -pub struct HavocBytesMutator +pub struct HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, R: Rand, { scheduled: SM, - phantom: PhantomData<(C, F, I, R, S)>, + phantom: PhantomData<(C, I, R, S)>, } -impl Mutator for HavocBytesMutator +impl Mutator for HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, R: Rand, { /// Mutate bytes - fn mutate( - &self, - fuzzer: &F, - state: &mut S, - input: &mut I, - stage_idx: i32, - ) -> Result<(), Error> { - self.scheduled.mutate(fuzzer, state, input, stage_idx)?; + fn mutate(&self, state: &mut S, input: &mut I, stage_idx: i32) -> Result<(), Error> { + self.scheduled.mutate(state, input, stage_idx)?; /*let num = self.scheduled.iterations(state, input); for _ in 0..num { let idx = self.scheduled.schedule(14, state, input); @@ -226,9 +208,9 @@ where } } -impl HasMaxSize for HavocBytesMutator +impl HasMaxSize for HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, @@ -245,9 +227,9 @@ where } } -impl HavocBytesMutator +impl HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, @@ -264,7 +246,7 @@ where } } -impl Default for HavocBytesMutator> +impl Default for HavocBytesMutator> where I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, @@ -273,7 +255,7 @@ where { /// Create a new HavocBytesMutator instance wrapping StdScheduledMutator fn default() -> Self { - let mut scheduled = StdScheduledMutator::::new(); + let mut scheduled = StdScheduledMutator::::new(); scheduled.add_mutation(mutation_bitflip); scheduled.add_mutation(mutation_byteflip); scheduled.add_mutation(mutation_byteinc); diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 252b17fcfb..f0d6ff352a 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -30,9 +30,8 @@ impl TokensMetadata { } /// Insert a dictionary token -pub fn mutation_tokeninsert( +pub fn mutation_tokeninsert( mutator: &M, - _: &F, state: &mut S, input: &mut I, ) -> Result @@ -77,9 +76,8 @@ where } /// Overwrite with a dictionary token -pub fn mutation_tokenreplace( +pub fn mutation_tokenreplace( _: &M, - _: &F, state: &mut S, input: &mut I, ) -> Result diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 01e729ac0f..abb2aadce4 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -1,15 +1,21 @@ pub mod mutational; 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. /// Multiple stages will be scheduled one by one for each input. -pub trait Stage { +pub trait Stage +where + EM: EventManager, + E: Executor, + I: Input, +{ /// Run the stage fn perform( &self, - fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, @@ -17,10 +23,14 @@ pub trait Stage { ) -> Result<(), Error>; } -pub trait StagesTuple { +pub trait StagesTuple +where + EM: EventManager, + E: Executor, + I: Input, +{ fn perform_all( &self, - fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, @@ -28,28 +38,33 @@ pub trait StagesTuple { ) -> Result<(), Error>; } -impl StagesTuple for () { - fn perform_all(&self, _: &F, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> { +impl StagesTuple for () +where + EM: EventManager, + E: Executor, + I: Input, +{ + fn perform_all(&self, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> { Ok(()) } } -impl StagesTuple for (Head, Tail) +impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + TupleList, + Head: Stage, + Tail: StagesTuple + TupleList, + EM: EventManager, + E: Executor, + I: Input, { fn perform_all( &self, - fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { - self.0 - .perform(fuzzer, state, executor, manager, corpus_idx)?; - self.1 - .perform_all(fuzzer, state, executor, manager, corpus_idx) + self.0.perform(state, executor, manager, corpus_idx)?; + self.1.perform_all(state, executor, manager, corpus_idx) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index d69c2e3600..59a283f893 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -18,9 +18,9 @@ use crate::{ /// A Mutational stage is the stage in a fuzzing run that mutates inputs. /// Mutational stages will usually have a range of mutations that are /// being applied to the input one by one, between executions. -pub trait MutationalStage: Stage +pub trait MutationalStage: Stage where - M: Mutator, + M: Mutator, I: Input, S: HasCorpus + Evaluator, C: Corpus, @@ -40,7 +40,6 @@ where /// Runs this (mutational) stage for the given testcase fn perform_mutational( &self, - fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, @@ -54,12 +53,11 @@ where .borrow_mut() .load_input()? .clone(); - self.mutator() - .mutate(fuzzer, state, &mut input_mut, i as i32)?; + self.mutator().mutate(state, &mut input_mut, i as i32)?; 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(()) } @@ -69,9 +67,9 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; /// The default mutational stage #[derive(Clone, Debug)] -pub struct StdMutationalStage +pub struct StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, S: HasCorpus + Evaluator + HasRand, C: Corpus, @@ -81,13 +79,13 @@ where R: Rand, { mutator: M, - phantom: PhantomData<(C, E, EM, F, I, OT, R, S)>, + phantom: PhantomData<(C, E, EM, I, OT, R, S)>, } -impl MutationalStage - for StdMutationalStage +impl MutationalStage + for StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, S: HasCorpus + Evaluator + HasRand, C: Corpus, @@ -114,10 +112,9 @@ where } } -impl Stage - for StdMutationalStage +impl Stage for StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, S: HasCorpus + Evaluator + HasRand, C: Corpus, @@ -129,19 +126,18 @@ where #[inline] fn perform( &self, - fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { - self.perform_mutational(fuzzer, state, executor, manager, corpus_idx) + self.perform_mutational(state, executor, manager, corpus_idx) } } -impl StdMutationalStage +impl StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, S: HasCorpus + Evaluator + HasRand, C: Corpus,