From 8b22a06ec9bfbfafe2295cee103d49dbcccd89b8 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 18 Feb 2021 17:12:27 +0100 Subject: [PATCH 01/10] unfinished generic magics --- libafl/src/corpus/minset.rs | 225 ++++++++++++++++++++++++++++ libafl/src/corpus/mod old.rs | 103 +++++++++++++ libafl/src/corpus/mod.rs | 250 ++++++++++++++++++++++---------- libafl/src/feedbacks/mod.rs | 7 - libafl/src/fuzzer.rs | 142 ++++++++++++++++++ libafl/src/lib.rs | 137 +---------------- libafl/src/mutators/mod.rs | 13 +- libafl/src/stages/mod.rs | 134 ++++++----------- libafl/src/stages/mutational.rs | 138 +++++++----------- libafl/src/state/mod.rs | 79 +++++++--- libafl/src/utils.rs | 4 +- 11 files changed, 810 insertions(+), 422 deletions(-) create mode 100644 libafl/src/corpus/minset.rs create mode 100644 libafl/src/corpus/mod old.rs create mode 100644 libafl/src/fuzzer.rs diff --git a/libafl/src/corpus/minset.rs b/libafl/src/corpus/minset.rs new file mode 100644 index 0000000000..713573ceb6 --- /dev/null +++ b/libafl/src/corpus/minset.rs @@ -0,0 +1,225 @@ +use alloc::{borrow::ToOwned, vec::Vec}; +use core::{cell::RefCell, iter::Iterator, marker::PhantomData}; +use serde::{Deserialize, Serialize}; + +use crate::{ + corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::{HasLen, Input}, utils::Rand, Error, +}; + +pub trait FavFactor: Serialize + serde::de::DeserializeOwned + 'static +{ + fn compute(testcase: &Testcase) -> Result + where + I: Input; +} + +pub struct LenTimeMulFavFactor {} + +// TODO time as Duration and put len into Testcase +impl FavFactor for LenTimeMulFavFactor { + fn compute(entry: &Testcase) -> Result + where + I: Input + HasLen + { + entry.exec_time() * entry.load_input().len() + } +} + +pub trait CorpusMinimizer { + fn update_score(corpus: &mut C, idx: usize) -> Result<(), Error> + where + C: Corpus, + I: Input, + R: Rand; + + fn cull(corpus: &mut C) -> Result<(), Error> + where + C: Corpus, + I: Input, + R: Rand; +} + +pub struct FavCorpusMinimizer +where + F: FavFactor +{ + phantom: PhantomData +} + +impl CorpusMinimizer for FavCorpusMinimizer +where + F: FavFactor +{ + fn update_score(corpus: &mut C, idx: usize) -> Result<(), Error> + where + C: Corpus, + I: Input, + R: Rand + { + + } + + fn cull(corpus: &mut C) -> Result<(), Error> + where + C: Corpus, + I: Input, + R: Rand + { + + } +} + + +#[derive(Serialize, Deserialize)] +pub struct NoveltiesMeta { + novelties: Vec, +} +// impl Iterator + +/// A Queue-like corpus, wrapping an existing Corpus instance +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub struct MinSetCorpus +where + C: Corpus, + F: FavFactor, + I: Input, + IT: Iterator, + R: Rand, +{ + corpus: C, + pos: usize, + // TODO rebase minset on remove() + minset: HashSet, + top_rated: HashMap, + phantom: PhantomData<(F, I, IT, R)>, +} + +impl HasTestcaseVec for MinSetCorpus +where + C: Corpus, + I: Input, + R: Rand, +{ + #[inline] + fn entries(&self) -> &[RefCell>] { + self.corpus.entries() + } + #[inline] + fn entries_mut(&mut self) -> &mut Vec>> { + self.corpus.entries_mut() + } +} + +impl Corpus for MinSetCorpus +where + C: Corpus, + I: Input, + R: Rand, +{ + /// Returns the number of elements + #[inline] + fn count(&self) -> usize { + self.corpus.count() + } + + // TODO change add to return Result + #[inline] + fn add(&mut self, entry: Testcase) -> usize { + let idx = self.corpus.add(entry); + self.update_score(idx).unwrap(); + idx + } + + /// Removes an entry from the corpus, returning it if it was present. + #[inline] + fn remove(&mut self, entry: &Testcase) -> Option> { + self.corpus.remove(entry) + } + + /// Gets a random entry + #[inline] + fn random_entry(&self, rand: &mut R) -> Result<(&RefCell>, usize), Error> { + self.corpus.random_entry(rand) + } + + /// Returns the testacase we currently use + #[inline] + fn current_testcase(&self) -> (&RefCell>, usize) { + (self.get(self.pos - 1), self.pos - 1) + } + + /// Gets the next entry + #[inline] + fn next(&mut self, _rand: &mut R) -> Result<(&RefCell>, usize), Error> { + self.cull(); + self.pos += 1; + if self.corpus.count() == 0 { + return Err(Error::Empty("Corpus".to_owned())); + } + if self.pos > self.corpus.count() { + // TODO: Always loop or return informational error? + self.pos = 1; + self.cycles += 1; + } + Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1)) + } +} + +impl MinSetCorpus +where + C: Corpus, + I: Input, + R: Rand, +{ + pub fn new(corpus: C) -> Self { + Self { + corpus: corpus, + phantom: PhantomData, + } + } + + #[inline] + pub fn corpus(&self) -> &C { + &self.corpus + } + + #[inline] + pub fn corpus_mut(&mut self) -> &mut C { + &mut self.corpus + } + + // TODO move this functions and top rated to another struct + // create something like MinSetCorpus<.., FavMinimizer> + + pub fn update_score(&mut self, idx: usize) -> Result<(), Error> { + let factor = F::compute(self.entries()[idx].borrow())?; + for elem in entry.get::() { + if let val = self.top_rated.get_mut(elem) { + if factor > F::compute(self.entries()[val].borrow())? { + continue + } + } + + let _ = self.top_rated.insert(elem, idx); + } + } + + pub fn cull(&mut self) { + let mut acc = HashSet::new(); + self.minset.clear(); + + for key in self.top_rated.keys() { + if !acc.contains(key) { + let idx = self.top_rated.get(key).unwrap(); + let entry = self.entries()[idx].borrow(); + for elem in entry.get::() { + acc.insert(elem); + } + + self.minset.insert(idx); + } + } + } +} + diff --git a/libafl/src/corpus/mod old.rs b/libafl/src/corpus/mod old.rs new file mode 100644 index 0000000000..86eeaf961f --- /dev/null +++ b/libafl/src/corpus/mod old.rs @@ -0,0 +1,103 @@ +//! Corpuses contain the testcases, either in mem, on disk, or somewhere else. +//! They will hand out the next fuzz target, potentially doing basic scheduling. + +pub mod testcase; +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::QueueCorpus; + +use alloc::{borrow::ToOwned, vec::Vec}; +use core::{cell::RefCell, ptr}; + +use crate::{inputs::Input, utils::Rand, Error}; + +/// A way to obtain the containing testcase entries +pub trait HasTestcaseVec +where + I: Input, +{ + /// Get the entries vector field + fn entries(&self) -> &[RefCell>]; + + /// Get the entries vector field (mutable) + fn entries_mut(&mut self) -> &mut Vec>>; +} + +/// Corpus with all current testcases +pub trait Corpus: HasTestcaseVec + serde::Serialize + serde::de::DeserializeOwned +where + I: Input, + R: Rand, +{ + /// Returns the number of elements + #[inline] + fn count(&self) -> usize { + self.entries().len() + } + + // TODO implement a was_fuzzed counter + + /// Add an entry to the corpus and return its index + #[inline] + fn add(&mut self, testcase: Testcase) -> usize { + self.entries_mut().push(RefCell::new(testcase)); + self.entries().len() - 1 + } + + /// Replaces the testcase at the given idx + fn replace(&mut self, idx: usize, testcase: Testcase) -> Result<(), Error> { + if self.entries_mut().len() < idx { + return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx))); + } + self.entries_mut()[idx] = RefCell::new(testcase); + Ok(()) + } + + /// Get by id + #[inline] + fn get(&self, idx: usize) -> &RefCell> { + &self.entries()[idx] + } + + /// Removes an entry from the corpus, returning it if it was present. + #[inline] + fn remove(&mut self, entry: &Testcase) -> Option> { + match self + .entries() + .iter() + .position(|x| ptr::eq(x.as_ptr(), entry)) + { + Some(i) => Some(self.entries_mut().remove(i).into_inner()), + None => None, + } + } + + /// Gets a random entry + #[inline] + fn random_entry(&self, rand: &mut R) -> Result<(&RefCell>, usize), Error> { + if self.count() == 0 { + Err(Error::Empty("No entries in corpus".to_owned())) + } else { + let len = { self.entries().len() }; + let id = rand.below(len as u64) as usize; + Ok((self.get(id), id)) + } + } + + // TODO: IntoIter + /// Gets the next entry + fn next(&mut self, rand: &mut R) -> Result<(&RefCell>, usize), Error>; + + /// Returns the testacase we currently use + fn current_testcase(&self) -> (&RefCell>, usize); +} + diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 14b87341bd..3ac1b49265 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -1,102 +1,204 @@ //! Corpuses contain the testcases, either in mem, on disk, or somewhere else. -//! They will hand out the next fuzz target, potentially doing basic scheduling. pub mod testcase; pub use testcase::Testcase; -pub mod inmemory; -pub use inmemory::InMemoryCorpus; +use alloc::{vec::Vec}; +use core::{cell::RefCell}; -#[cfg(feature = "std")] -pub mod ondisk; -#[cfg(feature = "std")] -pub use ondisk::OnDiskCorpus; - -pub mod queue; -pub use queue::QueueCorpus; - -use alloc::{borrow::ToOwned, vec::Vec}; -use core::{cell::RefCell, ptr}; - -use crate::{inputs::Input, utils::Rand, Error}; - -/// A way to obtain the containing testcase entries -pub trait HasTestcaseVec -where - I: Input, -{ - /// Get the entries vector field - fn entries(&self) -> &[RefCell>]; - - /// Get the entries vector field (mutable) - fn entries_mut(&mut self) -> &mut Vec>>; -} +use crate::{ + inputs::Input, + state::{HasCorpus, HasRand}, + utils::Rand, + Error, +}; /// Corpus with all current testcases -pub trait Corpus: HasTestcaseVec + serde::Serialize + serde::de::DeserializeOwned +pub trait Corpus: serde::Serialize + serde::de::DeserializeOwned where I: Input, - R: Rand, { /// Returns the number of elements - #[inline] - fn count(&self) -> usize { - self.entries().len() - } - - // TODO implement a was_fuzzed counter + fn count(&self) -> usize; /// Add an entry to the corpus and return its index - #[inline] - fn add(&mut self, testcase: Testcase) -> usize { - self.entries_mut().push(RefCell::new(testcase)); - self.entries().len() - 1 - } + fn add(&mut self, testcase: Testcase) -> Result; /// Replaces the testcase at the given idx - fn replace(&mut self, idx: usize, testcase: Testcase) -> Result<(), Error> { - if self.entries_mut().len() < idx { - return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx))); - } - self.entries_mut()[idx] = RefCell::new(testcase); + fn replace(&mut self, idx: usize, testcase: Testcase) -> Result<(), Error>; + + /// Removes an entry from the corpus, returning it if it was present. + fn remove(&mut self, idx: usize) -> Result>, Error>; + + /// Get by id + fn get(&self, idx: usize) -> Result<&RefCell>, Error>; +} + +pub trait CorpusScheduler { + + /// Add an entry to the corpus and return its index + fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> + where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand + { Ok(()) } - /// Get by id - #[inline] - fn get(&self, idx: usize) -> &RefCell> { - &self.entries()[idx] + /// Replaces the testcase at the given idx + fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> + where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand + { + Ok(()) } /// Removes an entry from the corpus, returning it if it was present. - #[inline] - fn remove(&mut self, entry: &Testcase) -> Option> { - match self - .entries() - .iter() - .position(|x| ptr::eq(x.as_ptr(), entry)) - { - Some(i) => Some(self.entries_mut().remove(i).into_inner()), - None => None, - } - } - - /// Gets a random entry - #[inline] - fn random_entry(&self, rand: &mut R) -> Result<(&RefCell>, usize), Error> { - if self.count() == 0 { - Err(Error::Empty("No entries in corpus".to_owned())) - } else { - let len = { self.entries().len() }; - let id = rand.below(len as u64) as usize; - Ok((self.get(id), id)) - } + fn on_remove(&self, state: &mut S, idx: usize, testcase: &Option>) -> Result<(), Error> + where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand + { + Ok(()) } // TODO: IntoIter /// Gets the next entry - fn next(&mut self, rand: &mut R) -> Result<(&RefCell>, usize), Error>; + fn next(&self, state: &mut S) -> Result + where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand; - /// Returns the testacase we currently use - fn current_testcase(&self) -> (&RefCell>, usize); +} + +pub struct RandCorpusScheduler {} + +impl CorpusScheduler for RandCorpusScheduler { + /// Gets the next entry at random + fn next(state: &mut S) -> Result + where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand + { + if state.corpus().count() == 0 { + Err(Error::Empty("No entries in corpus".to_owned())) + } else { + let len = state.corpus().count(); + let id = state.rand_mut().below(len as u64) as usize; + Ok(id) + } + } +} + +pub struct InMemoryCorpus +where + I: Input, +{ + entries: Vec>>, +} + +impl Corpus for InMemoryCorpus +where + I: Input, +{ + + /// Returns the number of elements + #[inline] + fn count(&self) -> usize { + self.entries.len() + } + + /// Add an entry to the corpus and return its index + #[inline] + fn add(&mut self, testcase: Testcase) -> Result { + self.entries.push(RefCell::new(testcase)); + Ok(self.entries.len() - 1) + } + + /// Replaces the testcase at the given idx + #[inline] + 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(()) + } + + /// Removes an entry from the corpus, returning it if it was present. + #[inline] + fn remove(&mut self, idx: usize) -> Result>, Error> { + if idx >= self.entries.len() { + Ok(None) + } else { + Ok(Some(self.entries.remove(idx).into_inner())) + } + } + + /// Get by id + #[inline] + fn get(&self, idx: usize) -> Result<&RefCell>, Error> { + Ok(&self.entries[idx]) + } + + /*/// Add an entry to the corpus and return its index + #[inline] + fn add(state: &mut S, testcase: Testcase) -> Result + where + S: HasCorpus + HasRand, + R: Rand + { + state.corpus_mut().entries.push(RefCell::new(testcase)); + let idx = state.corpus().entries.len() - 1; + // Scheduler hook + SC::on_add(state, idx, state.corpus().entries[idx].borrow())?; + Ok(idx) + } + + /// Replaces the testcase at the given idx + #[inline] + fn replace(state: &mut S, idx: usize, testcase: Testcase) -> Result<(), Error> + where + S: HasCorpus + HasRand, + R: Rand + { + if state.corpus().entries.len() < idx { + return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx))); + } + state.corpus_mut().entries[idx] = RefCell::new(testcase); + // Scheduler hook + SC::on_replace(state, idx, state.corpus().entries[idx])?; + Ok(()) + } + + /// Removes an entry from the corpus, returning it if it was present. + #[inline] + fn remove(state: &mut S, idx: usize) -> Result>, Error> + where + S: HasCorpus + HasRand, + R: Rand + { + let testcase = match state.corpus_mut() + .entries + .iter() + .position(|x| ptr::eq(x.as_ptr(), entry)) + { + Some(i) => Some(state.corpus_mut().entries.remove(i).into_inner()), + None => None, + }; + // Scheduler hook + SC::on_remove(state, idx, &testcase)?; + Ok(testcase) + }*/ } diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 724b0d4d41..76ac3abad5 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -148,13 +148,6 @@ where self.0.discard_metadata(input)?; self.1.discard_metadata_all(input) } - - /* - fn restore_state_from_all(&mut self, restore_from: &Self) -> Result<(), Error> { - self.0.restore_from(restore_from.0)?; - self.1.restore_state_from_all(restore_from.1)?; - } - */ } /// Is a crash feedback diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs new file mode 100644 index 0000000000..50cc535425 --- /dev/null +++ b/libafl/src/fuzzer.rs @@ -0,0 +1,142 @@ +use core::{marker::PhantomData}; + +use crate::{ + corpus::{CorpusScheduler}, + events::{Event, EventManager}, + executors::{Executor}, + inputs::Input, + stages::StagesTuple, + utils::{current_milliseconds, current_time}, + Error +}; + +/// Holds a set of stages +pub trait HasStages +where + ST: StagesTuple, +{ + fn stages(&self) -> &ST; + + fn stages_mut(&mut self) -> &mut ST; +} + +/// Holds a set of stages +pub trait HasCorpusScheduler +where + CS: CorpusScheduler, +{ + fn scheduler(&self) -> &CS; + + fn scheduler_mut(&mut self) -> &mut CS; +} + +/// The main fuzzer trait. +pub trait Fuzzer: HasCorpusScheduler + HasStages +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + fn fuzz_one( + &mut self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result + where + EM: EventManager, + E: Executor, + { + let idx = self.scheduler().next(state)?; + + self.stages() + .perform_all(executor, state, manager, idx)?; + + manager.process(state, executor)?; + Ok(idx) + } + + fn fuzz_loop( + &mut self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result + where + EM: EventManager, + E: Executor, + { + let mut last = current_milliseconds(); + loop { + self.fuzz_one(executor, state, manager)?; + let cur = current_milliseconds(); + if cur - last > 60 * 100 { + last = cur; + manager.fire( + state, + Event::UpdateStats { + executions: state.executions(), + time: current_time(), + phantom: PhantomData, + }, + )? + } + } + } +} + +/// Your default fuzzer instance, for everyday use. +#[derive(Clone, Debug)] +pub struct StdFuzzer +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + scheduler: CS, + stages: ST, +} + +impl HasStages for StdFuzzer +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + fn stages(&self) -> &ST { + &self.stages + } + + fn stages_mut(&mut self) -> &mut ST { + &mut self.stages + } +} + +impl HasCorpusScheduler for StdFuzzer +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + fn scheduler(&self) -> &CS { + &self.scheduler + } + + fn scheduler_mut(&mut self) -> &mut CS { + &mut self.scheduler + } +} + +impl StdFuzzer +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + pub fn new(scheduler: CS, stages: ST) -> Self { + Self { + scheduler: scheduler, + stages: stages, + } + } +} diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 2906185e91..e1e11c07c1 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -25,144 +25,15 @@ pub mod state; pub mod stats; pub mod utils; +pub mod fuzzer; +pub use fuzzer::*; + use alloc::string::String; -use core::{fmt, marker::PhantomData}; -use corpus::Corpus; -use events::{Event, EventManager}; -use executors::{Executor, HasObservers}; -use feedbacks::FeedbacksTuple; -use inputs::Input; -use observers::ObserversTuple; -use stages::StagesTuple; -use state::{HasCorpus, State}; -use utils::{current_milliseconds, current_time, Rand}; +use core::{fmt}; #[cfg(feature = "std")] use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error}; -/// The main fuzzer trait. -pub trait Fuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - fn stages(&self) -> &ST; - - fn stages_mut(&mut self) -> &mut ST; - - fn fuzz_one( - &mut self, - rand: &mut R, - executor: &mut E, - state: &mut State, - manager: &mut EM, - ) -> Result { - let (_, idx) = state.corpus_mut().next(rand)?; - - self.stages_mut() - .perform_all(rand, executor, state, manager, idx)?; - - manager.process(state, executor)?; - Ok(idx) - } - - fn fuzz_loop( - &mut self, - rand: &mut R, - executor: &mut E, - state: &mut State, - manager: &mut EM, - ) -> Result<(), Error> { - let mut last = current_milliseconds(); - loop { - self.fuzz_one(rand, executor, state, manager)?; - let cur = current_milliseconds(); - if cur - last > 60 * 100 { - last = cur; - manager.fire( - state, - Event::UpdateStats { - executions: state.executions(), - time: current_time(), - phantom: PhantomData, - }, - )? - } - } - } -} - -/// Your default fuzzer instance, for everyday use. -#[derive(Clone, Debug)] -pub struct StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - stages: ST, - phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>, -} - -impl Fuzzer - for StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - fn stages(&self) -> &ST { - &self.stages - } - - fn stages_mut(&mut self) -> &mut ST { - &mut self.stages - } -} - -impl StdFuzzer -where - ST: StagesTuple, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - pub fn new(stages: ST) -> Self { - Self { - stages: stages, - phantom: PhantomData, - } - } -} - /// Main error struct for AFL #[derive(Debug)] pub enum Error { diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index d8f0bd9ac2..8498b700ea 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -8,10 +8,7 @@ pub mod token_mutations; pub use token_mutations::*; use crate::{ - corpus::Corpus, inputs::Input, - state::{HasCorpus, HasMetadata}, - utils::Rand, Error, }; @@ -20,24 +17,20 @@ use crate::{ /// A mutator takes input, and mutates it. /// Simple as that. -pub trait Mutator +pub trait Mutator where - C: Corpus, I: Input, - R: Rand, - S: HasCorpus + HasMetadata, { /// Mutate a given input - fn mutate( + fn mutate( &mut self, - rand: &mut R, state: &mut S, input: &mut I, stage_idx: i32, ) -> Result<(), Error>; /// Post-process given the outcome of the execution - fn post_exec( + fn post_exec( &mut self, _state: &mut S, _is_interesting: u32, diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 2ea67a3a03..805e4e7ca9 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -5,125 +5,83 @@ use crate::{ bolts::tuples::TupleList, corpus::Corpus, events::EventManager, - executors::{Executor, HasObservers}, - feedbacks::FeedbacksTuple, + executors::{Executor}, inputs::Input, - observers::ObserversTuple, - state::State, - utils::Rand, 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 + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, + I: Input { /// Run the stage - fn perform( - &mut self, - rand: &mut R, + fn perform( + &self, executor: &mut E, - state: &mut State, + state: &mut S, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error>; + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor; } -pub trait StagesTuple +pub trait StagesTuple where - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, + I: Input { - fn perform_all( - &mut self, - rand: &mut R, + fn perform_all( + &self, executor: &mut E, - state: &mut State, + state: &mut S, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error>; - fn for_each(&self, f: fn(&dyn Stage)); - fn for_each_mut(&mut self, f: fn(&mut dyn Stage)); + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor; } -impl StagesTuple for () +impl StagesTuple for () where - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, + I: Input { - fn perform_all( - &mut self, - _rand: &mut R, - _executor: &mut E, - _state: &mut State, - _manager: &mut EM, - _corpus_idx: usize, - ) -> Result<(), Error> { + fn perform_all( + &self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor + { Ok(()) } - fn for_each(&self, _f: fn(&dyn Stage)) {} - fn for_each_mut(&mut self, _f: fn(&mut dyn Stage)) {} } -impl StagesTuple - for (Head, Tail) +impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + TupleList, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, + Head: Stage, + Tail: StagesTuple + TupleList, + I: Input { - fn perform_all( - &mut self, - rand: &mut R, + fn perform_all( + &self, executor: &mut E, - state: &mut State, + state: &mut S, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> { - self.0.perform(rand, executor, state, manager, corpus_idx)?; - self.1 - .perform_all(rand, executor, state, manager, corpus_idx) - } - - fn for_each(&self, f: fn(&dyn Stage)) { - f(&self.0); - self.1.for_each(f) - } - - fn for_each_mut(&mut self, f: fn(&mut dyn Stage)) { - f(&mut self.0); - self.1.for_each_mut(f) + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor + { + self.0.perform(executor, state, manager, corpus_idx)?; + self.1 .perform_all(executor, state, manager, corpus_idx) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 9c6c7fbf3a..7255e957bc 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -2,14 +2,12 @@ use core::marker::PhantomData; use crate::{ events::EventManager, - executors::{Executor, HasObservers}, - feedbacks::FeedbacksTuple, + executors::{Executor}, inputs::Input, mutators::Mutator, - observers::ObserversTuple, stages::Corpus, stages::Stage, - state::{HasCorpus, State}, + state::{HasRand}, utils::Rand, Error, }; @@ -19,19 +17,10 @@ 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>, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, + M: Mutator, I: Input, - R: Rand, { /// The mutator registered for this stage fn mutator(&self) -> &M; @@ -40,22 +29,21 @@ where fn mutator_mut(&mut self) -> &mut M; /// Gets the number of iterations this mutator should run for. - /// This call uses internal mutability, so it may change for each call - #[inline] - fn iterations(&mut self, rand: &mut R) -> usize { - 1 + rand.below(128) as usize - } + fn iterations(&mut self, state: &mut S) -> usize; /// Runs this (mutational) stage for the given testcase - fn perform_mutational( - &mut self, - rand: &mut R, + fn perform_mutational( + &self, executor: &mut E, - state: &mut State, + state: &mut S, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> { - let num = self.iterations(rand); + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor + { + let num = self.iterations(state); for i in 0..num { let mut input_mut = state .corpus() @@ -64,7 +52,7 @@ where .load_input()? .clone(); self.mutator_mut() - .mutate(rand, state, &mut input_mut, i as i32)?; + .mutate(state, &mut input_mut, i as i32)?; let fitness = state.process_input(input_mut, executor, manager)?; @@ -74,38 +62,23 @@ where } } -#[derive(Clone, Debug)] +pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; + /// The default mutational stage -pub struct StdMutationalStage +#[derive(Clone, Debug)] +pub struct StdMutationalStage where - C: Corpus, - E: Executor + HasObservers, - EM: EventManager, - FT: FeedbacksTuple, + M: Mutator, I: Input, - M: Mutator>, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - R: Rand, { mutator: M, - phantom: PhantomData<(EM, E, OC, OFT, OT, FT, C, I, R)>, + phantom: PhantomData, } -impl MutationalStage - for StdMutationalStage +impl MutationalStage for StdMutationalStage where - C: Corpus, - E: Executor + HasObservers, - EM: EventManager, - FT: FeedbacksTuple, + M: Mutator, I: Input, - M: Mutator>, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - R: Rand, { /// The mutator, added to this stage #[inline] @@ -118,47 +91,42 @@ where fn mutator_mut(&mut self) -> &mut M { &mut self.mutator } -} -impl Stage - for StdMutationalStage -where - M: Mutator>, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, - I: Input, - R: Rand, -{ - #[inline] - fn perform( - &mut self, - rand: &mut R, - executor: &mut E, - state: &mut State, - manager: &mut EM, - corpus_idx: usize, - ) -> Result<(), Error> { - self.perform_mutational(rand, executor, state, manager, corpus_idx) + /// Gets the number of iterations as a random number + fn iterations(&mut self, state: &mut S) -> usize + where + S: HasRand, + R: Rand + { + 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize } } -impl StdMutationalStage +impl Stage for StdMutationalStage where - M: Mutator>, - EM: EventManager, - E: Executor + HasObservers, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - C: Corpus, + M: Mutator, + I: Input, +{ + #[inline] + fn perform( + &self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), Error> + where + EM: EventManager, + E: Executor + { + self.perform_mutational(executor, state, manager, corpus_idx) + } +} + +impl StdMutationalStage +where + M: Mutator, I: Input, - R: Rand, { /// Creates a new default mutational stage pub fn new(mutator: M) -> Self { diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 983b556509..9337ad98a0 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -25,11 +25,10 @@ use crate::{ use crate::inputs::bytes::BytesInput; /// Trait for elements offering a corpus -pub trait HasCorpus +pub trait HasCorpus where - C: Corpus, + C: Corpus, I: Input, - R: Rand, { /// The testcase corpus fn corpus(&self) -> &C; @@ -37,6 +36,17 @@ where fn corpus_mut(&mut self) -> &mut C; } +/// Trait for elements offering a rand +pub trait HasRand +where + R: Rand, +{ + /// The rand instance + fn rand(&self) -> &R; + /// The rand instance (mut) + fn rand_mut(&mut self) -> &mut R; +} + /// Trait for elements offering metadata pub trait HasMetadata { /// A map, storing all metadata @@ -59,13 +69,15 @@ pub trait HasMetadata { #[serde(bound = "FT: serde::de::DeserializeOwned")] pub struct State where - C: Corpus, + C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, { + /// RNG instance + rand: R, /// How many times the executor ran the harness/target executions: usize, /// The corpus @@ -82,16 +94,16 @@ where /// Objective Feedbacks objective_feedbacks: OFT, - phantom: PhantomData<(R, I)>, + phantom: PhantomData, } #[cfg(feature = "std")] impl State where - C: Corpus, + C: Corpus, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, { pub fn load_from_directory( @@ -101,7 +113,7 @@ where in_dir: &Path, ) -> Result<(), Error> where - C: Corpus, + C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, EM: EventManager, @@ -143,7 +155,7 @@ where in_dirs: &[PathBuf], ) -> Result<(), Error> where - C: Corpus, + C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, EM: EventManager, @@ -164,13 +176,34 @@ where } } -impl HasCorpus for State +impl HasRand for State where - C: Corpus, + C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, + OFT: FeedbacksTuple, +{ + /// The rand instance + fn rand(&self) -> &R { + &self.rand + } + + /// The rand instance (mut) + fn rand_mut(&mut self) -> &mut R { + &mut self.rand + } +} + + +impl HasCorpus for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + OC: Corpus, OFT: FeedbacksTuple, { /// Returns the corpus @@ -187,11 +220,11 @@ where /// Trait for elements offering metadata impl HasMetadata for State where - C: Corpus, + C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, { /// Get all the metadata into an HashMap @@ -209,11 +242,11 @@ where impl State where - C: Corpus, + C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, { /// Get executions @@ -299,7 +332,7 @@ where where E: Executor + HasObservers, OT: ObserversTuple, - C: Corpus, + C: Corpus, EM: EventManager, { executor.pre_exec_observers()?; @@ -356,11 +389,11 @@ where #[inline] pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result, Error> where - C: Corpus, + C: Corpus, { if fitness > 0 { let testcase = self.input_to_testcase(input, fitness)?; - Ok(Some(self.corpus_mut().add(testcase))) + Ok(Some(C::add(self, testcase)?)) } else { self.discard_input(&input)?; Ok(None) @@ -371,7 +404,7 @@ where #[inline] pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result, Error> where - C: Corpus, + C: Corpus, { if fitness > 0 { let testcase = self.input_to_testcase(input, fitness)?; @@ -394,7 +427,7 @@ where where E: Executor + HasObservers, OT: ObserversTuple, - C: Corpus, + C: Corpus, EM: EventManager, { let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?; @@ -435,7 +468,7 @@ where ) -> Result<(), Error> where G: Generator, - C: Corpus, + C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, EM: EventManager, diff --git a/libafl/src/utils.rs b/libafl/src/utils.rs index 3b206f22f3..b0eff77df9 100644 --- a/libafl/src/utils.rs +++ b/libafl/src/utils.rs @@ -1,7 +1,7 @@ //! Utility functions for AFL use core::{cell::RefCell, debug_assert, fmt::Debug, time}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; use xxhash_rust::xxh3::xxh3_64_with_seed; #[cfg(feature = "std")] @@ -10,7 +10,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; pub type StdRand = RomuTrioRand; /// Ways to get random around here -pub trait Rand: Debug + Serialize { +pub trait Rand: Debug + Serialize + DeserializeOwned { // Sets the seed of this Rand fn set_seed(&mut self, seed: u64); From 95281dbfef22416284193ce016a48f2aa5d8d8a0 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 19 Feb 2021 12:15:09 +0100 Subject: [PATCH 02/10] mutations --- libafl/src/fuzzer.rs | 108 +++++--- libafl/src/mutators/mutations.rs | 328 +++++++++++++------------ libafl/src/mutators/scheduled.rs | 147 ++++++----- libafl/src/mutators/token_mutations.rs | 16 +- libafl/src/stages/mod.rs | 4 +- libafl/src/stages/mutational.rs | 15 +- 6 files changed, 335 insertions(+), 283 deletions(-) diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index 50cc535425..e6abc6a7a8 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -1,26 +1,28 @@ use core::{marker::PhantomData}; use crate::{ - corpus::{CorpusScheduler}, + corpus::{CorpusScheduler, Corpus}, events::{Event, EventManager}, executors::{Executor}, inputs::Input, stages::StagesTuple, - utils::{current_milliseconds, current_time}, + state::{HasRand, HasCorpus}, + utils::{Rand, current_milliseconds, current_time}, Error }; /// Holds a set of stages -pub trait HasStages +pub trait HasStages where - ST: StagesTuple, + ST: StagesTuple, + I: Input { fn stages(&self) -> &ST; fn stages_mut(&mut self) -> &mut ST; } -/// Holds a set of stages +/// Holds a scheduler pub trait HasCorpusScheduler where CS: CorpusScheduler, @@ -31,7 +33,7 @@ where } /// The main fuzzer trait. -pub trait Fuzzer: HasCorpusScheduler + HasStages +pub trait Fuzzer: HasCorpusScheduler + HasStages where CS: CorpusScheduler, ST: StagesTuple, @@ -45,16 +47,7 @@ where ) -> Result where EM: EventManager, - E: Executor, - { - let idx = self.scheduler().next(state)?; - - self.stages() - .perform_all(executor, state, manager, idx)?; - - manager.process(state, executor)?; - Ok(idx) - } + E: Executor; fn fuzz_loop( &mut self, @@ -64,25 +57,7 @@ where ) -> Result where EM: EventManager, - E: Executor, - { - let mut last = current_milliseconds(); - loop { - self.fuzz_one(executor, state, manager)?; - let cur = current_milliseconds(); - if cur - last > 60 * 100 { - last = cur; - manager.fire( - state, - Event::UpdateStats { - executions: state.executions(), - time: current_time(), - phantom: PhantomData, - }, - )? - } - } - } + E: Executor; } /// Your default fuzzer instance, for everyday use. @@ -97,7 +72,7 @@ where stages: ST, } -impl HasStages for StdFuzzer +impl HasStages for StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, @@ -127,6 +102,67 @@ where } } +impl Fuzzer for StdFuzzer +where + CS: CorpusScheduler, + ST: StagesTuple, + I: Input +{ + fn fuzz_one( + &mut self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result + where + EM: EventManager, + E: Executor, + S: HasCorpus + HasRand, + C: Corpus, + R: Rand + { + let idx = self.scheduler().next(state)?; + + self.stages() + .perform_all(executor, state, manager, idx)?; + + manager.process(state, executor)?; + Ok(idx) + } + + fn fuzz_loop( + &mut self, + executor: &mut E, + state: &mut S, + manager: &mut EM, + ) -> Result + where + EM: EventManager, + E: Executor, + S: HasCorpus + HasRand, + C: Corpus, + R: Rand + { + let mut last = current_milliseconds(); + loop { + self.fuzz_one(executor, state, manager)?; + let cur = current_milliseconds(); + if cur - last > 60 * 100 { + last = cur; + manager.fire( + state, + Event::UpdateStats { + executions: state.executions(), + time: current_time(), + phantom: PhantomData, + }, + )? + } + } + } +} + + impl StdFuzzer where CS: CorpusScheduler, diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index fc1368deb0..19f72ebeae 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -1,7 +1,8 @@ use crate::{ inputs::{HasBytesVec, Input}, - mutators::Corpus, + corpus::Corpus, mutators::*, + state::{HasRand, HasCorpus}, utils::Rand, Error, }; @@ -15,42 +16,6 @@ use std::{ io::{BufRead, BufReader}, }; -const ARITH_MAX: u64 = 35; - -const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; -const INTERESTING_16: [i16; 19] = [ - -128, -1, 0, 1, 16, 32, 64, 100, 127, -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767, -]; -const INTERESTING_32: [i32; 27] = [ - -128, - -1, - 0, - 1, - 16, - 32, - 64, - 100, - 127, - -32768, - -129, - 128, - 255, - 256, - 512, - 1000, - 1024, - 4096, - 32767, - -2147483648, - -100663046, - -32769, - 32768, - 65535, - 65536, - 100663045, - 2147483647, -]; - /// The result of a mutation. /// If the mutation got skipped, the target /// will not be executed with the returned input. @@ -62,24 +27,21 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = - fn(&mut M, &mut R, &mut S, &mut I) -> Result; +pub type MutationFunction = + fn(&mut M, &mut S, &mut I) -> Result; -pub trait ComposedByMutations +pub trait ComposedByMutations where - C: Corpus, I: Input, - R: Rand, - S: HasCorpus + HasMetadata, { /// 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 @@ -125,21 +87,58 @@ fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) { } } + +const ARITH_MAX: u64 = 35; + +const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; +const INTERESTING_16: [i16; 19] = [ + -128, -1, 0, 1, 16, 32, 64, 100, 127, -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767, +]; +const INTERESTING_32: [i32; 27] = [ + -128, + -1, + 0, + 1, + 16, + 32, + 64, + 100, + 127, + -32768, + -129, + 128, + 255, + 256, + 512, + 1000, + 1024, + 4096, + 32767, + -2147483648, + -100663046, + -32769, + 32768, + 65535, + 65536, + 100663045, + 2147483647, +]; + /// Bitflip mutation for inputs with a bytes vector pub fn mutation_bitflip( _: &mut M, - rand: &mut R, - _: &mut S, + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, - R: Rand, + S: HasRand, + R: Rand { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let bit = rand.below((input.bytes().len() << 3) as u64) as usize; + let bit = state.rand_mut().below((input.bytes().len() << 3) as u64) as usize; unsafe { // Moar speed, no bound check *input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128 >> (bit & 7)) as u8; @@ -150,18 +149,19 @@ where pub fn mutation_byteflip( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check *input.bytes_mut().get_unchecked_mut(idx) ^= 0xff; @@ -172,18 +172,19 @@ where pub fn mutation_byteinc( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx); @@ -195,18 +196,19 @@ where pub fn mutation_bytedec( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx); @@ -218,18 +220,19 @@ where pub fn mutation_byteneg( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check *input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx)); @@ -240,21 +243,22 @@ where pub fn mutation_byterand( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check - *input.bytes_mut().get_unchecked_mut(idx) = rand.below(256) as u8; + *input.bytes_mut().get_unchecked_mut(idx) = state.rand_mut().below(256) as u8; } Ok(MutationResult::Mutated) } @@ -262,23 +266,24 @@ where pub fn mutation_byteadd( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut u8; - let num = 1 + rand.below(ARITH_MAX) as u8; - match rand.below(2) { + let num = 1 + state.rand_mut().below(ARITH_MAX) as u8; + match state.rand_mut().below(2) { 0 => *ptr = (*ptr).wrapping_add(num), _ => *ptr = (*ptr).wrapping_sub(num), }; @@ -289,23 +294,24 @@ where pub fn mutation_wordadd( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() < 2 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64 - 1) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64 - 1) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u16; - let num = 1 + rand.below(ARITH_MAX) as u16; - match rand.below(4) { + let num = 1 + state.rand_mut().below(ARITH_MAX) as u16; + match state.rand_mut().below(4) { 0 => *ptr = (*ptr).wrapping_add(num), 1 => *ptr = (*ptr).wrapping_sub(num), 2 => *ptr = ((*ptr).swap_bytes().wrapping_add(num)).swap_bytes(), @@ -318,23 +324,24 @@ where pub fn mutation_dwordadd( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() < 4 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64 - 3) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64 - 3) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u32; - let num = 1 + rand.below(ARITH_MAX) as u32; - match rand.below(4) { + let num = 1 + state.rand_mut().below(ARITH_MAX) as u32; + match state.rand_mut().below(4) { 0 => *ptr = (*ptr).wrapping_add(num), 1 => *ptr = (*ptr).wrapping_sub(num), 2 => *ptr = ((*ptr).swap_bytes().wrapping_add(num)).swap_bytes(), @@ -347,23 +354,24 @@ where pub fn mutation_qwordadd( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() < 8 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64 - 7) as usize; + let idx = state.rand_mut().below(input.bytes().len() as u64 - 7) as usize; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u64; - let num = 1 + rand.below(ARITH_MAX) as u64; - match rand.below(4) { + let num = 1 + state.rand_mut().below(ARITH_MAX) as u64; + match state.rand_mut().below(4) { 0 => *ptr = (*ptr).wrapping_add(num), 1 => *ptr = (*ptr).wrapping_sub(num), 2 => *ptr = ((*ptr).swap_bytes().wrapping_add(num)).swap_bytes(), @@ -376,19 +384,20 @@ where pub fn mutation_byteinteresting( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64) as usize; - let val = INTERESTING_8[rand.below(INTERESTING_8.len() as u64) as usize] as u8; + let idx = state.rand_mut().below(input.bytes().len() as u64) as usize; + let val = INTERESTING_8[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u8; unsafe { // Moar speed, no bound check *input.bytes_mut().get_unchecked_mut(idx) = val; @@ -399,23 +408,24 @@ where pub fn mutation_wordinteresting( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() < 2 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64 - 1) as usize; - let val = INTERESTING_16[rand.below(INTERESTING_8.len() as u64) as usize] as u16; + let idx = state.rand_mut().below(input.bytes().len() as u64 - 1) as usize; + let val = INTERESTING_16[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u16; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u16; - if rand.below(2) == 0 { + if state.rand_mut().below(2) == 0 { *ptr = val; } else { *ptr = val.swap_bytes(); @@ -427,23 +437,24 @@ where pub fn mutation_dwordinteresting( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { if input.bytes().len() < 4 { Ok(MutationResult::Skipped) } else { - let idx = rand.below(input.bytes().len() as u64 - 3) as usize; - let val = INTERESTING_32[rand.below(INTERESTING_8.len() as u64) as usize] as u32; + let idx = state.rand_mut().below(input.bytes().len() as u64 - 3) as usize; + let val = INTERESTING_32[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u32; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u32; - if rand.below(2) == 0 { + if state.rand_mut().below(2) == 0 { *ptr = val; } else { *ptr = val.swap_bytes(); @@ -455,12 +466,13 @@ where pub fn mutation_bytesdelete( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); @@ -468,8 +480,8 @@ where return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64) as usize; - let len = rand.below((size - off) as u64) as usize; + let off = state.rand_mut().below(size as u64) as usize; + let len = state.rand_mut().below((size - off) as u64) as usize; input.bytes_mut().drain(off..off + len); Ok(MutationResult::Mutated) @@ -478,18 +490,18 @@ where pub fn mutation_bytesexpand( // TODO: max_size instead of mutator? mutator: &mut M, - rand: &mut R, - _: &mut S, + state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); - let off = rand.below((size + 1) as u64) as usize; - let mut len = 1 + rand.below(16) as usize; + let off = state.rand_mut().below((size + 1) as u64) as usize; + let mut len = 1 + state.rand_mut().below(16) as usize; if size + len > mutator.max_size() { if mutator.max_size() > size { @@ -507,18 +519,18 @@ where pub fn mutation_bytesinsert( mutator: &mut M, - rand: &mut R, - _: &mut S, + state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); - let off = rand.below((size + 1) as u64) as usize; - let mut len = 1 + rand.below(16) as usize; + let off = state.rand_mut().below((size + 1) as u64) as usize; + let mut len = 1 + state.rand_mut().below(16) as usize; if size + len > mutator.max_size() { if mutator.max_size() > size { @@ -528,7 +540,7 @@ where } } - let val = input.bytes()[rand.below(size as u64) as usize]; + let val = input.bytes()[state.rand_mut().below(size as u64) as usize]; input.bytes_mut().resize(size + len, 0); buffer_self_copy(input.bytes_mut(), off, off + len, size - off); @@ -539,18 +551,19 @@ where pub fn mutation_bytesrandinsert( mutator: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); - let off = rand.below((size + 1) as u64) as usize; - let mut len = 1 + rand.below(16) as usize; + let off = state.rand_mut().below((size + 1) as u64) as usize; + let mut len = 1 + state.rand_mut().below(16) as usize; if size + len > mutator.max_size() { if mutator.max_size() > size { @@ -560,7 +573,7 @@ where } } - let val = rand.below(256) as u8; + let val = state.rand_mut().below(256) as u8; input.bytes_mut().resize(size + len, 0); buffer_self_copy(input.bytes_mut(), off, off + len, size - off); @@ -571,22 +584,23 @@ where pub fn mutation_bytesset( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64) as usize; - let len = 1 + rand.below(min(16, size - off) as u64) as usize; + let off = state.rand_mut().below(size as u64) as usize; + let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize; - let val = input.bytes()[rand.below(size as u64) as usize]; + let val = input.bytes()[state.rand_mut().below(size as u64) as usize]; buffer_set(input.bytes_mut(), off, len, val); @@ -595,22 +609,23 @@ where pub fn mutation_bytesrandset( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } - let off = rand.below(size as u64) as usize; - let len = 1 + rand.below(min(16, size - off) as u64) as usize; + let off = state.rand_mut().below(size as u64) as usize; + let len = 1 + state.rand_mut().below(min(16, size - off) as u64) as usize; - let val = rand.below(256) as u8; + let val = state.rand_mut().below(256) as u8; buffer_set(input.bytes_mut(), off, len, val); @@ -619,12 +634,13 @@ where pub fn mutation_bytescopy( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); @@ -632,9 +648,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(input.bytes().len() as u64) as usize; - let to = rand.below(input.bytes().len() as u64) as usize; - let len = 1 + rand.below((size - max(from, to)) as u64) as usize; + let from = state.rand_mut().below(input.bytes().len() as u64) as usize; + let to = state.rand_mut().below(input.bytes().len() as u64) as usize; + let len = 1 + state.rand_mut().below((size - max(from, to)) as u64) as usize; buffer_self_copy(input.bytes_mut(), from, to, len); @@ -643,12 +659,13 @@ where pub fn mutation_bytesswap( _: &mut M, - rand: &mut R, - _: &mut S, + + state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, + S: HasRand, R: Rand, { let size = input.bytes().len(); @@ -656,9 +673,9 @@ where return Ok(MutationResult::Skipped); } - let first = rand.below(input.bytes().len() as u64) as usize; - let second = rand.below(input.bytes().len() as u64) as usize; - let len = 1 + rand.below((size - max(first, second)) as u64) as usize; + let first = state.rand_mut().below(input.bytes().len() as u64) as usize; + let second = state.rand_mut().below(input.bytes().len() as u64) as usize; + let len = 1 + state.rand_mut().below((size - max(first, second)) as u64) as usize; let tmp = input.bytes()[first..(first + len)].to_vec(); buffer_self_copy(input.bytes_mut(), second, first, len); @@ -670,21 +687,20 @@ where /// Crossover insert mutation pub fn mutation_crossover_insert( mutator: &mut M, - rand: &mut R, state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, - C: Corpus, + C: Corpus, I: Input + HasBytesVec, R: Rand, - S: HasCorpus, + S: HasRand + HasCorpus, { let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.corpus().random_entry(rand)?; + let (other_testcase, idx) = state.random_corpus_entry()?; if idx == state.corpus().current_testcase().1 { return Ok(MutationResult::Skipped); } @@ -697,9 +713,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(other_size as u64) as usize; - let to = rand.below(size as u64) as usize; - let mut len = rand.below((other_size - from) as u64) as usize; + let from = state.rand_mut().below(other_size as u64) as usize; + let to = state.rand_mut().below(size as u64) as usize; + let mut len = state.rand_mut().below((other_size - from) as u64) as usize; if size + len > mutator.max_size() { if mutator.max_size() > size { @@ -719,20 +735,20 @@ where /// Crossover replace mutation pub fn mutation_crossover_replace( _: &mut M, - rand: &mut R, + state: &mut S, input: &mut I, ) -> Result where - C: Corpus, + C: Corpus, I: Input + HasBytesVec, R: Rand, - S: HasCorpus, + S: HasRand + HasCorpus, { let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.corpus().random_entry(rand)?; + let (other_testcase, idx) = state.random_corpus_entry()?; if idx == state.corpus().current_testcase().1 { return Ok(MutationResult::Skipped); } @@ -745,9 +761,9 @@ where return Ok(MutationResult::Skipped); } - let from = rand.below(other_size as u64) as usize; - let len = rand.below(min(other_size - from, size) as u64) as usize; - let to = rand.below((size - len) as u64) as usize; + let from = state.rand_mut().below(other_size as u64) as usize; + let len = state.rand_mut().below(min(other_size - from, size) as u64) as usize; + let to = state.rand_mut().below((size - len) as u64) as usize; buffer_copy(input.bytes_mut(), other.bytes(), from, to, len); @@ -773,18 +789,18 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { /// Splicing mutation from AFL pub fn mutation_splice( _: &mut M, - rand: &mut R, + state: &mut S, input: &mut I, ) -> Result where - C: Corpus, + C: Corpus, I: Input + HasBytesVec, R: Rand, - S: HasCorpus, + S: HasRand + HasCorpus, { // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.corpus().random_entry(rand)?; + let (other_testcase, idx) = state.random_corpus_entry()?; if idx == state.corpus().current_testcase().1 { return Ok(MutationResult::Skipped); } @@ -805,7 +821,7 @@ where counter += 1; }; - let split_at = rand.between(first_diff as u64, last_diff as u64) as usize; + let split_at = state.rand_mut().between(first_diff as u64, last_diff as u64) as usize; input .bytes_mut() .splice(split_at.., other.bytes()[split_at..].iter().cloned()); diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 993f8b11d1..29cf4ef807 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -1,72 +1,69 @@ +use crate::inputs::HasBytesVec; use alloc::vec::Vec; use core::{fmt, default::Default, marker::PhantomData}; use fmt::Debug; use crate::{ - inputs::{HasBytesVec, Input}, - mutators::{Corpus, *}, - state::{HasCorpus, HasMetadata}, + inputs::{Input}, + mutators::{Mutator, HasMaxSize, DEFAULT_MAX_SIZE}, + state::{HasRand, HasCorpus, HasMetadata}, + corpus::Corpus, utils::Rand, Error, }; -pub trait ScheduledMutator: - Mutator + ComposedByMutations +pub use crate::mutators::mutations::*; +pub use crate::mutators::token_mutations::*; + +pub trait ScheduledMutator: Mutator + ComposedByMutations where - C: Corpus, I: Input, - R: Rand, - S: HasCorpus + HasMetadata, { /// Compute the number of iterations used to apply stacked mutations - #[inline] - fn iterations(&mut self, rand: &mut R, _input: &I) -> u64 { - 1 << (1 + rand.below(6)) - } + fn iterations(&mut self, state: &mut S, input: &I) -> u64; + //{ + // 1 << (1 + state.rand_mut().below(6)) + //} /// Get the next mutation to apply - #[inline] - fn schedule(&mut self, mutations_count: usize, rand: &mut R, _input: &I) -> usize { - debug_assert!(mutations_count > 0); - rand.below(mutations_count as u64) as usize - } + fn schedule(&mut self, mutations_count: usize, state: &mut S, input: &I) -> usize; + //{ + // debug_assert!(mutations_count > 0); + // rand.below(mutations_count as u64) as usize + //} /// New default implementation for mutate /// Implementations must forward mutate() to this method fn scheduled_mutate( &mut self, - rand: &mut R, state: &mut S, input: &mut I, _stage_idx: i32, ) -> Result<(), Error> { - let num = self.iterations(rand, input); + let num = self.iterations(state, input); for _ in 0..num { - let idx = self.schedule(self.mutations_count(), rand, input); - self.mutation_by_idx(idx)(self, rand, state, input)?; + let idx = self.schedule(self.mutations_count(), state, input); + self.mutation_by_idx(idx)(self, state, input)?; } Ok(()) } } #[derive(Clone)] -pub struct StdScheduledMutator +pub struct StdScheduledMutator where - C: Corpus, - I: Input, - R: Rand, - S: HasCorpus + HasMetadata, -{ - mutations: Vec>, +I: Input, +R: Rand, +S: HasRand,{ + mutations: Vec>, max_size: usize, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -79,12 +76,11 @@ where } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { fn mutate( &mut self, @@ -93,19 +89,18 @@ where input: &mut I, _stage_idx: i32, ) -> Result<(), Error> { - self.scheduled_mutate(rand, state, input, _stage_idx) + self.scheduled_mutate(state, input, _stage_idx) } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { #[inline] - fn mutation_by_idx(&self, index: usize) -> MutationFunction { + fn mutation_by_idx(&self, index: usize) -> MutationFunction { self.mutations[index] } @@ -115,27 +110,25 @@ 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 - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { // Just use the default methods } -impl HasMaxSize for StdScheduledMutator +impl HasMaxSize for StdScheduledMutator where - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { #[inline] fn max_size(&self) -> usize { @@ -148,12 +141,11 @@ where } } -impl StdScheduledMutator +impl StdScheduledMutator where - C: Corpus, I: Input, R: Rand, - S: HasCorpus + HasMetadata, + S: HasRand, { /// Create a new StdScheduledMutator instance without mutations and corpus pub fn new() -> Self { @@ -164,7 +156,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,27 +164,27 @@ where } } -#[derive(Clone, Debug)] /// Schedule some selected byte level mutations given a ScheduledMutator type -pub struct HavocBytesMutator +#[derive(Clone, Debug)] +pub struct HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, - C: Corpus, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, + S: HasRand + HasCorpus + HasMetadata, + C: Corpus, R: Rand, - S: HasCorpus + HasMetadata, { scheduled: SM, - phantom: PhantomData<(C, I, R, S)>, + phantom: PhantomData<(I, R, S)>, } -impl Mutator for HavocBytesMutator +impl Mutator for HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, - C: Corpus, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, + S: HasRand + HasCorpus + HasMetadata, + C: Corpus, R: Rand, - S: HasCorpus + HasMetadata, { /// Mutate bytes fn mutate( @@ -202,10 +194,10 @@ where input: &mut I, stage_idx: i32, ) -> Result<(), Error> { - self.scheduled.mutate(rand, state, input, stage_idx)?; - /*let num = self.scheduled.iterations(rand, input); + self.scheduled.mutate(state, input, stage_idx)?; + /*let num = self.scheduled.iterations(state, input); for _ in 0..num { - let idx = self.scheduled.schedule(14, rand, input); + let idx = self.scheduled.schedule(14, state, input); let mutation = match idx { 0 => mutation_bitflip, 1 => mutation_byteflip, @@ -222,19 +214,19 @@ where 11 => mutation_dwordinteresting, _ => mutation_splice, }; - mutation(self, rand, state, input)?; + mutation(self, state, input)?; }*/ Ok(()) } } -impl HasMaxSize for HavocBytesMutator +impl HasMaxSize for HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, - C: Corpus, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, + S: HasRand + HasCorpus + HasMetadata, + C: Corpus, R: Rand, - S: HasCorpus + HasMetadata, { #[inline] fn max_size(&self) -> usize { @@ -247,13 +239,13 @@ where } } -impl HavocBytesMutator +impl HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, - C: Corpus, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, + S: HasRand + HasCorpus + HasMetadata, + C: Corpus, R: Rand, - S: HasCorpus + HasMetadata, { /// Create a new HavocBytesMutator instance given a ScheduledMutator to wrap pub fn new(mut scheduled: SM) -> Self { @@ -266,16 +258,17 @@ where } } -impl Default for HavocBytesMutator, C, I, R, S> +impl Default for HavocBytesMutator> where - C: Corpus, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, + S: HasRand + HasCorpus + HasMetadata, + C: Corpus, R: Rand, - S: HasCorpus + HasMetadata, { /// 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); @@ -317,6 +310,7 @@ where } } +/* #[cfg(test)] mod tests { use crate::{ @@ -390,3 +384,4 @@ mod tests { } } } +*/ \ No newline at end of file diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index a075fdaa4e..597f7c3d80 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -3,6 +3,7 @@ use crate::{ inputs::{HasBytesVec, Input}, + state::{HasRand, HasCorpus, HasMetadata}, mutators::*, utils::Rand, Error, @@ -31,15 +32,14 @@ impl TokensMetadata { /// Insert a dictionary token pub fn mutation_tokeninsert( mutator: &mut M, - rand: &mut R, state: &mut S, input: &mut I, ) -> Result where M: HasMaxSize, I: Input + HasBytesVec, + S: HasMetadata + HasRand, R: Rand, - S: HasMetadata, { let meta; match state.metadata().get::() { @@ -53,10 +53,10 @@ where if meta.tokens.len() == 0 { return Ok(MutationResult::Skipped); } - let token = &meta.tokens[rand.below(meta.tokens.len() as u64) as usize]; + let token = &meta.tokens[state.rand_mut().below(meta.tokens.len() as u64) as usize]; let size = input.bytes().len(); - let off = rand.below((size + 1) as u64) as usize; + let off = state.rand_mut().below((size + 1) as u64) as usize; let mut len = token.len(); if size + len > mutator.max_size() { @@ -77,14 +77,14 @@ where /// Overwrite with a dictionary token pub fn mutation_tokenreplace( _: &mut M, - rand: &mut R, state: &mut S, input: &mut I, ) -> Result where + M: HasMaxSize, I: Input + HasBytesVec, + S: HasMetadata + HasRand, R: Rand, - S: HasMetadata, { let size = input.bytes().len(); if size == 0 { @@ -103,9 +103,9 @@ where if meta.tokens.len() == 0 { return Ok(MutationResult::Skipped); } - let token = &meta.tokens[rand.below(meta.tokens.len() as u64) as usize]; + let token = &meta.tokens[state.rand_mut().below(meta.tokens.len() as u64) as usize]; - let off = rand.below(size as u64) as usize; + let off = state.rand_mut().below(size as u64) as usize; let mut len = token.len(); if off + len > size { diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 805e4e7ca9..dda5bb1ed0 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -66,8 +66,8 @@ where impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + TupleList, + Head: Stage, + Tail: StagesTuple + TupleList, I: Input { fn perform_all( diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 7255e957bc..73f78765df 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -9,6 +9,7 @@ use crate::{ stages::Stage, state::{HasRand}, utils::Rand, + state::HasCorpus, Error, }; @@ -32,7 +33,7 @@ where fn iterations(&mut self, state: &mut S) -> usize; /// Runs this (mutational) stage for the given testcase - fn perform_mutational( + fn perform_mutational( &self, executor: &mut E, state: &mut S, @@ -41,13 +42,15 @@ where ) -> Result<(), Error> where EM: EventManager, - E: Executor + E: Executor, + S: HasCorpus, + C: Corpus { let num = self.iterations(state); for i in 0..num { let mut input_mut = state .corpus() - .get(corpus_idx) + .get(corpus_idx)? .borrow_mut() .load_input()? .clone(); @@ -108,7 +111,7 @@ where I: Input, { #[inline] - fn perform( + fn perform( &self, executor: &mut E, state: &mut S, @@ -117,7 +120,9 @@ where ) -> Result<(), Error> where EM: EventManager, - E: Executor + E: Executor, + S: HasCorpus, + C: Corpus { self.perform_mutational(executor, state, manager, corpus_idx) } From a939f052d3b72a0e664ace3e54804e7bb307b292 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 19 Feb 2021 15:46:39 +0100 Subject: [PATCH 03/10] fuzzer arg missing atm --- libafl/src/corpus/mod.rs | 55 +- libafl/src/corpus/testcase.rs | 12 + libafl/src/events/llmp.rs | 109 ++-- libafl/src/events/logger.rs | 42 +- libafl/src/events/mod.rs | 68 +-- libafl/src/executors/inprocess.rs | 97 +--- libafl/src/executors/mod.rs | 22 +- libafl/src/fuzzer.rs | 8 +- libafl/src/lib.rs | 2 + libafl/src/mutators/scheduled.rs | 5 +- libafl/src/mutators/token_mutations.rs | 2 +- libafl/src/stages/mutational.rs | 8 +- libafl/src/state/mod.rs | 685 +++++++++++++++---------- 13 files changed, 530 insertions(+), 585 deletions(-) diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 3ac1b49265..126c2b2898 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -5,6 +5,7 @@ pub use testcase::Testcase; use alloc::{vec::Vec}; use core::{cell::RefCell}; +use serde::{Serialize, Deserialize}; use crate::{ inputs::Input, @@ -101,6 +102,8 @@ impl CorpusScheduler for RandCorpusScheduler { } } +#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "I: serde::de::DeserializeOwned")] pub struct InMemoryCorpus where I: Input, @@ -108,7 +111,7 @@ where entries: Vec>>, } -impl Corpus for InMemoryCorpus +impl Corpus for InMemoryCorpus where I: Input, { @@ -151,54 +154,4 @@ where fn get(&self, idx: usize) -> Result<&RefCell>, Error> { Ok(&self.entries[idx]) } - - /*/// Add an entry to the corpus and return its index - #[inline] - fn add(state: &mut S, testcase: Testcase) -> Result - where - S: HasCorpus + HasRand, - R: Rand - { - state.corpus_mut().entries.push(RefCell::new(testcase)); - let idx = state.corpus().entries.len() - 1; - // Scheduler hook - SC::on_add(state, idx, state.corpus().entries[idx].borrow())?; - Ok(idx) - } - - /// Replaces the testcase at the given idx - #[inline] - fn replace(state: &mut S, idx: usize, testcase: Testcase) -> Result<(), Error> - where - S: HasCorpus + HasRand, - R: Rand - { - if state.corpus().entries.len() < idx { - return Err(Error::KeyNotFound(format!("Index {} out of bounds", idx))); - } - state.corpus_mut().entries[idx] = RefCell::new(testcase); - // Scheduler hook - SC::on_replace(state, idx, state.corpus().entries[idx])?; - Ok(()) - } - - /// Removes an entry from the corpus, returning it if it was present. - #[inline] - fn remove(state: &mut S, idx: usize) -> Result>, Error> - where - S: HasCorpus + HasRand, - R: Rand - { - let testcase = match state.corpus_mut() - .entries - .iter() - .position(|x| ptr::eq(x.as_ptr(), entry)) - { - Some(i) => Some(state.corpus_mut().entries.remove(i).into_inner()), - None => None, - }; - // Scheduler hook - SC::on_remove(state, idx, &testcase)?; - Ok(testcase) - }*/ } diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index d43812d8b3..984f5530e2 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -159,6 +159,18 @@ where } } + /// Create a new Testcase instace given an input and a fitness + #[inline] + pub fn with_fitness(input: I, fitness: u32) -> Self { + Testcase { + input: Some(input.into()), + filename: None, + fitness: fitness, + metadatas: SerdeAnyMap::new(), + exec_time: None, + } + } + #[inline] pub fn default() -> Self { Testcase { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 867eaadb31..fe46d05054 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -1,6 +1,7 @@ use crate::bolts::llmp::LlmpSender; use alloc::{string::ToString, vec::Vec}; use core::{marker::PhantomData, time::Duration}; +use serde::{Serialize, de::DeserializeOwned}; #[cfg(feature = "std")] use crate::bolts::llmp::LlmpReceiver; @@ -16,16 +17,13 @@ use crate::{ llmp::{self, LlmpClient, LlmpClientDescription, Tag}, shmem::ShMem, }, - corpus::Corpus, events::{BrokerEventResult, Event, EventManager}, executors::ExitKind, executors::{Executor, HasObservers}, - feedbacks::FeedbacksTuple, inputs::Input, observers::ObserversTuple, - state::State, + state::{IfInteresting}, stats::Stats, - utils::Rand, Error, }; @@ -250,21 +248,17 @@ where } // Handle arriving events in the client - fn handle_in_client( + fn handle_in_client( &mut self, - state: &mut State, + state: &mut S, sender_id: u32, event: Event, _executor: &mut E, ) -> Result<(), Error> where - C: Corpus, E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, OT: ObserversTuple, + S: IfInteresting { match event { Event::NewTestcase { @@ -284,7 +278,7 @@ where // TODO include ExitKind in NewTestcase let fitness = state.is_interesting(&input, &observers, ExitKind::Ok)?; if fitness > 0 { - if !state.add_if_interesting(input, fitness)?.is_none() { + if !state.add_if_interesting(&input, fitness)?.is_none() { #[cfg(feature = "std")] println!("Added received Testcase"); } @@ -317,19 +311,15 @@ where } } - fn process( + fn process( &mut self, - state: &mut State, + state: &mut S, executor: &mut E, ) -> Result where - C: Corpus, E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, OT: ObserversTuple, + S: IfInteresting { // TODO: Get around local event copy by moving handle_in_client let mut events = vec![]; @@ -358,19 +348,11 @@ where Ok(count) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut S, event: Event, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - I: Input, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - { + ) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; Ok(()) @@ -380,17 +362,13 @@ where /// Serialize the current state and corpus during an executiont to bytes. /// On top, add the current llmp event manager instance to be restored /// This method is needed when the fuzzer run crashes and has to restart. -pub fn serialize_state_mgr( - state: &State, +pub fn serialize_state_mgr( + state: &S, mgr: &LlmpEventManager, ) -> Result, Error> where - C: Corpus, - FT: FeedbacksTuple, I: Input, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, + S: Serialize, SH: ShMem, ST: Stats, { @@ -398,20 +376,16 @@ where } /// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)` -pub fn deserialize_state_mgr( +pub fn deserialize_state_mgr( state_corpus_serialized: &[u8], -) -> Result<(State, LlmpEventManager), Error> +) -> Result<(S, LlmpEventManager), Error> where - C: Corpus, - FT: FeedbacksTuple, I: Input, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, + S: DeserializeOwned, SH: ShMem, ST: Stats, { - let tuple: (State, _) = postcard::from_bytes(&state_corpus_serialized)?; + let tuple: (S, _) = postcard::from_bytes(&state_corpus_serialized)?; Ok(( tuple.0, LlmpEventManager::existing_client_from_description(&tuple.1)?, @@ -447,16 +421,12 @@ where } /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. - fn on_restart( + fn on_restart( &mut self, - state: &mut State, + state: &mut S, ) -> Result<(), Error> where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, + S: Serialize, { // First, reset the page to 0 so the next iteration can read read from the beginning of this page unsafe { self.sender.reset() }; @@ -465,35 +435,24 @@ where .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) } - fn process( + fn process( &mut self, - state: &mut State, + state: &mut S, executor: &mut E, ) -> Result where - C: Corpus, E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, OT: ObserversTuple, + S: IfInteresting { self.llmp_mgr.process(state, executor) } - fn fire( + fn fire( &mut self, - state: &mut State, + state: &mut S, event: Event, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - { + ) -> Result<(), Error> { // Check if we are going to crash in the event, in which case we store our current state for the next runner self.llmp_mgr.fire(state, event) } @@ -530,24 +489,20 @@ where /// A restarting state is a combination of restarter and runner, that can be used on systems without `fork`. /// The restarter will start a new process each time the child crashes or timeouts. #[cfg(feature = "std")] -pub fn setup_restarting_mgr( +pub fn setup_restarting_mgr( //mgr: &mut LlmpEventManager, stats: ST, broker_port: u16, ) -> Result< ( - Option>, + Option, LlmpRestartingEventManager, ), Error, > where I: Input, - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, + S: DeserializeOwned, SH: ShMem, ST: Stats, { @@ -607,7 +562,7 @@ where // Restoring from a previous run, deserialize state and corpus. Some((_sender, _tag, msg)) => { println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); - let (state, mgr): (State, LlmpEventManager) = + let (state, mgr): (S, LlmpEventManager) = deserialize_state_mgr(&msg)?; (Some(state), LlmpRestartingEventManager::new(mgr, sender)) diff --git a/libafl/src/events/logger.rs b/libafl/src/events/logger.rs index 5fe97054aa..e96f5d3ac0 100644 --- a/libafl/src/events/logger.rs +++ b/libafl/src/events/logger.rs @@ -3,15 +3,10 @@ use alloc::{string::ToString, vec::Vec}; #[cfg(feature = "std")] #[cfg(unix)] use crate::{ - corpus::Corpus, events::{BrokerEventResult, Event, EventManager}, - executors::{Executor, HasObservers}, - feedbacks::FeedbacksTuple, + executors::{Executor}, inputs::Input, - observers::ObserversTuple, - state::State, stats::Stats, - utils::Rand, Error, }; @@ -33,19 +28,13 @@ where I: Input, ST: Stats, //CE: CustomEvent, { - fn process( + fn process( &mut self, - state: &mut State, + state: &mut S, _executor: &mut E, ) -> Result where - C: Corpus, - E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, + E: Executor { let count = self.events.len(); while self.events.len() > 0 { @@ -55,17 +44,11 @@ where Ok(count) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut S, event: Event, ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, { match Self::handle_in_broker(&mut self.stats, &event)? { BrokerEventResult::Forward => self.events.push(event), @@ -132,18 +115,11 @@ where } // Handle arriving events in the client - fn handle_in_client( + fn handle_in_client( &mut self, - _state: &mut State, + _state: &mut S, event: Event, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - { + ) -> Result<(), Error> { match event { _ => Err(Error::Unknown(format!( "Received illegal message that message should not have arrived: {:?}.", diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index b44c8923a5..1aa4f00440 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -9,13 +9,9 @@ use core::{fmt, marker::PhantomData, time::Duration}; use serde::{Deserialize, Serialize}; use crate::{ - corpus::Corpus, - executors::{Executor, HasObservers}, - feedbacks::FeedbacksTuple, + executors::{Executor}, inputs::Input, observers::ObserversTuple, - state::State, - utils::Rand, Error, }; @@ -162,19 +158,13 @@ where /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process( + fn process( &mut self, - state: &mut State, + state: &mut S, executor: &mut E, ) -> Result where - C: Corpus, - E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple; + E: Executor; /// Serialize all observers for this type and manager fn serialize_observers(&mut self, observers: &OT) -> Result, Error> @@ -194,17 +184,10 @@ where /// For restarting event managers, implement a way to forward state to their next peers. #[inline] - fn on_restart( + fn on_restart( &mut self, - _state: &mut State, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - { + _state: &mut S, + ) -> Result<(), Error> { Ok(()) } @@ -213,17 +196,11 @@ where fn await_restart_safe(&mut self) {} /// Send off an event to the broker - fn fire( + fn fire( &mut self, - _state: &mut State, + state: &mut S, event: Event, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple; + ) -> Result<(), Error>; } /// An eventmgr for tests, and as placeholder if you really don't need an event manager. @@ -235,35 +212,22 @@ impl EventManager for NopEventManager where I: Input, { - fn process( + fn process( &mut self, - _state: &mut State, + _state: &mut S, _executor: &mut E, ) -> Result where - C: Corpus, - E: Executor + HasObservers, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, + E: Executor, { Ok(0) } - fn fire( + fn fire( &mut self, - _state: &mut State, + _state: &mut S, _event: Event, - ) -> Result<(), Error> - where - C: Corpus, - FT: FeedbacksTuple, - R: Rand, - OC: Corpus, - OFT: FeedbacksTuple, - { + ) -> Result<(), Error> { Ok(()) } } diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 9f3b523719..2fbe02ad2e 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -54,52 +54,42 @@ where OT: ObserversTuple, { #[inline] - fn pre_exec( + fn pre_exec( &mut self, - _state: &mut State, - _event_mgr: &mut EM, - _input: &I, + state: &mut S, + event_mgr: &mut EM, + input: &I, ) -> Result<(), Error> where - R: Rand, - FT: FeedbacksTuple, - OC: Corpus, - OFT: FeedbacksTuple, - C: Corpus, EM: EventManager, { #[cfg(unix)] #[cfg(feature = "std")] unsafe { - set_oncrash_ptrs::( - _state, - _event_mgr, + set_oncrash_ptrs( + state, + event_mgr, self.observers(), - _input, + input, ); } Ok(()) } #[inline] - fn post_exec( + fn post_exec( &mut self, - _state: &State, + _state: &S, _event_mgr: &mut EM, _input: &I, ) -> Result<(), Error> where - R: Rand, - FT: FeedbacksTuple, - C: Corpus, EM: EventManager, - OC: Corpus, - OFT: FeedbacksTuple, { #[cfg(unix)] #[cfg(feature = "std")] unsafe { - reset_oncrash_ptrs::(); + reset_oncrash_ptrs(); } Ok(()) } @@ -148,8 +138,6 @@ where /// depnding on different corpus or state. /// * `name` - the name of this executor (to address it along the way) /// * `harness_fn` - the harness, executiong the function - /// * `on_crash_fn` - When an in-mem harness crashes, it may safe some state to continue fuzzing later. - /// Do that that in this function. The program will crash afterwards. /// * `observers` - the observers observing the target during execution pub fn new( name: &'static str, @@ -161,9 +149,9 @@ where where R: Rand, FT: FeedbacksTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, - C: Corpus, + C: Corpus, EM: EventManager, { #[cfg(feature = "std")] @@ -181,25 +169,6 @@ where } } -/* -unsafe fn tidy_up_on_exit(mgr: &EM) -where -EM: EventManager, -I: Input, -{ - - match manager.llmp { - IsClient { client } => { - let map = client.out_maps.last().unwrap(); - /// wait until we can drop the message safely. - map.await_save_to_unmap_blocking(); - /// Make sure all pages are unmapped. - drop(manager); - } - _ => (), - } -}*/ - #[cfg(feature = "std")] #[cfg(unix)] pub mod unix_signals { @@ -242,15 +211,15 @@ 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(); - pub unsafe extern "C" fn libaflrs_executor_inmem_handle_crash( + unsafe fn inmem_handle_crash( _sig: c_int, info: siginfo_t, _void: c_void, ) where EM: EventManager, - C: Corpus, + C: Corpus, OT: ObserversTuple, - OC: Corpus, + OC: Corpus, OFT: FeedbacksTuple, FT: FeedbacksTuple, I: Input, @@ -324,14 +293,14 @@ pub mod unix_signals { std::process::exit(1); } - pub unsafe extern "C" fn libaflrs_executor_inmem_handle_timeout( + unsafe fn inmem_handle_timeout( _sig: c_int, _info: siginfo_t, _void: c_void, ) where EM: EventManager, - C: Corpus, - OC: Corpus, + C: Corpus, + OC: Corpus, OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, @@ -384,21 +353,12 @@ pub mod unix_signals { } #[inline] - pub unsafe fn set_oncrash_ptrs( - state: &mut State, + pub unsafe fn set_oncrash_ptrs( + state: &mut S, event_mgr: &mut EM, observers: &OT, input: &I, - ) where - EM: EventManager, - C: Corpus, - OC: Corpus, - OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, - I: Input, - R: Rand, - { + ) { CURRENT_INPUT_PTR = input as *const _ as *const c_void; STATE_PTR = state as *mut _ as *mut c_void; EVENT_MGR_PTR = event_mgr as *mut _ as *mut c_void; @@ -406,19 +366,18 @@ pub mod unix_signals { } #[inline] - pub unsafe fn reset_oncrash_ptrs() { + pub unsafe fn reset_oncrash_ptrs() { CURRENT_INPUT_PTR = ptr::null(); STATE_PTR = ptr::null_mut(); EVENT_MGR_PTR = ptr::null_mut(); - OBSERVERS_PTR = ptr::null_mut(); + OBSERVERS_PTR = ptr::null(); } - // TODO clearly state that manager should be static (maybe put the 'static lifetime?) pub unsafe fn setup_crash_handlers() where EM: EventManager, - C: Corpus, - OC: Corpus, + C: Corpus, + OC: Corpus, OFT: FeedbacksTuple, OT: ObserversTuple, FT: FeedbacksTuple, @@ -441,7 +400,7 @@ pub mod unix_signals { libc::sigemptyset(&mut sa.sa_mask as *mut libc::sigset_t); sa.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK; sa.sa_sigaction = - libaflrs_executor_inmem_handle_crash:: as usize; + inmem_handle_crash:: as usize; for (sig, msg) in &[ (SIGSEGV, "segfault"), (SIGBUS, "sigbus"), @@ -456,7 +415,7 @@ pub mod unix_signals { } sa.sa_sigaction = - libaflrs_executor_inmem_handle_timeout:: as usize; + 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/executors/mod.rs b/libafl/src/executors/mod.rs index 77b6802a3a..7a4a794e0d 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -10,13 +10,9 @@ use core::marker::PhantomData; use crate::{ bolts::tuples::{MatchNameAndType, MatchType, Named, TupleList}, - corpus::Corpus, events::EventManager, - feedbacks::FeedbacksTuple, inputs::{HasTargetBytes, Input}, observers::ObserversTuple, - state::State, - utils::Rand, Error, }; @@ -84,18 +80,13 @@ where { #[inline] /// Called right before exexution starts - fn pre_exec( + fn pre_exec( &mut self, - _state: &mut State, + _state: &mut S, _event_mgr: &mut EM, _input: &I, ) -> Result<(), Error> where - R: Rand, - FT: FeedbacksTuple, - C: Corpus, - OC: Corpus, - OFT: FeedbacksTuple, EM: EventManager, { Ok(()) @@ -103,18 +94,13 @@ where #[inline] /// Called right after execution finished. - fn post_exec( + fn post_exec( &mut self, - _state: &State, + _state: &S, _event_mgr: &mut EM, _input: &I, ) -> Result<(), Error> where - R: Rand, - FT: FeedbacksTuple, - C: Corpus, - OC: Corpus, - OFT: FeedbacksTuple, EM: EventManager, { Ok(()) diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index e6abc6a7a8..e4d924749d 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -6,7 +6,7 @@ use crate::{ executors::{Executor}, inputs::Input, stages::StagesTuple, - state::{HasRand, HasCorpus}, + state::{HasRand, HasCorpus, HasExecutions}, utils::{Rand, current_milliseconds, current_time}, Error }; @@ -70,6 +70,7 @@ where { scheduler: CS, stages: ST, + phantom: PhantomData } impl HasStages for StdFuzzer @@ -139,7 +140,7 @@ where where EM: EventManager, E: Executor, - S: HasCorpus + HasRand, + S: HasCorpus + HasRand + HasExecutions, C: Corpus, R: Rand { @@ -152,7 +153,7 @@ where manager.fire( state, Event::UpdateStats { - executions: state.executions(), + executions: *state.executions(), time: current_time(), phantom: PhantomData, }, @@ -173,6 +174,7 @@ where Self { scheduler: scheduler, stages: stages, + phantom: PhantomData } } } diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index e1e11c07c1..0101e09da1 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -116,6 +116,7 @@ impl From for Error { } } +/* // TODO: no_std test #[cfg(feature = "std")] #[cfg(test)] @@ -198,3 +199,4 @@ mod tests { assert_eq!(state.corpus().count(), corpus_deserialized.count()); } } +*/ \ No newline at end of file diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 29cf4ef807..91da465ead 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -175,7 +175,7 @@ where R: Rand, { scheduled: SM, - phantom: PhantomData<(I, R, S)>, + phantom: PhantomData<(C, I, R, S)>, } impl Mutator for HavocBytesMutator @@ -258,9 +258,8 @@ where } } -impl Default for HavocBytesMutator> +impl Default for HavocBytesMutator> where - SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 597f7c3d80..71635a33bd 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -3,7 +3,7 @@ use crate::{ inputs::{HasBytesVec, Input}, - state::{HasRand, HasCorpus, HasMetadata}, + state::{HasRand, HasMetadata}, mutators::*, utils::Rand, Error, diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 73f78765df..2e292912ce 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -9,7 +9,7 @@ use crate::{ stages::Stage, state::{HasRand}, utils::Rand, - state::HasCorpus, + state::{HasCorpus, Evaluator}, Error, }; @@ -43,7 +43,7 @@ where where EM: EventManager, E: Executor, - S: HasCorpus, + S: HasCorpus + Evaluator, C: Corpus { let num = self.iterations(state); @@ -57,7 +57,7 @@ where self.mutator_mut() .mutate(state, &mut input_mut, i as i32)?; - let fitness = state.process_input(input_mut, executor, manager)?; + let fitness = state.evaluate_input(input_mut, executor, manager)?; self.mutator_mut().post_exec(state, fitness, i as i32)?; } @@ -121,7 +121,7 @@ where where EM: EventManager, E: Executor, - S: HasCorpus, + S: HasCorpus + Evaluator, C: Corpus { self.perform_mutational(executor, state, manager, corpus_idx) diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 9337ad98a0..bcfe3d11e7 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -1,6 +1,6 @@ //! The fuzzer, and state are the core pieces of every good fuzzer -use core::{fmt::Debug, marker::PhantomData}; +use core::{fmt::Debug, marker::PhantomData, time::Duration}; use serde::{Deserialize, Serialize}; #[cfg(feature = "std")] use std::{ @@ -36,6 +36,18 @@ where fn corpus_mut(&mut self) -> &mut C; } +/// Trait for elements offering a corpus of solutions +pub trait HasSolutions +where + C: Corpus, + I: Input, +{ + /// The solutions corpus + fn solutions(&self) -> &C; + /// The solutions corpus (mut) + fn solutions_mut(&mut self) -> &mut C; +} + /// Trait for elements offering a rand pub trait HasRand where @@ -64,46 +76,409 @@ pub trait HasMetadata { } } +/// Trait for elements offering a feedbacks tuple +pub trait HasFeedbacks +where + FT: FeedbacksTuple, + I: Input +{ + /// The feedbacks tuple + fn feedbacks(&self) -> &FT; + + /// The feedbacks tuple (mut) + 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, 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 +pub trait HasObjectives +where + FT: FeedbacksTuple, + I: Input +{ + /// The objective feedbacks tuple + fn objectives(&self) -> &FT; + + /// The objective feedbacks tuple (mut) + fn objectives_mut(&mut self) -> &mut FT; +} + +/// Trait for the execution counter +pub trait HasExecutions +{ + /// The executions counter + fn executions(&self) -> &usize; + + /// The executions counter (mut) + fn executions_mut(&mut self) -> &mut usize; +} + +/// Trait for the starting time +pub trait HasStartTime +{ + /// The starting time + fn start_time(&self) -> &Duration; + + /// The starting time (mut) + fn start_time_mut(&mut self) -> &mut Duration; +} + +/// Add to the state if interesting +pub trait IfInteresting +where + I: Input +{ + /// Evaluate if a set of observation channels has an interesting state + fn is_interesting( + &mut self, + input: &I, + observers: &OT, + exit_kind: ExitKind, + ) -> Result + where + OT: ObserversTuple; + + /// Adds this input to the corpus, if it's intersting, and return the index + fn add_if_interesting(&mut self, input: &I, fitness: u32) -> Result, Error>; +} + +/// Evaluate an input modyfing the state of the fuzzer and returning a fitness +pub trait Evaluator +where + I: Input, +{ + /// Runs the input and triggers observers and feedback + fn evaluate_input( + &mut self, + input: I, + executor: &mut E, + event_mgr: &mut EM, + ) -> Result + where + E: Executor, + EM: EventManager; +} + /// The state a fuzz run. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "FT: serde::de::DeserializeOwned")] -pub struct State +pub struct State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + SC: Corpus, OFT: FeedbacksTuple, { /// RNG instance rand: R, /// How many times the executor ran the harness/target executions: usize, + /// At what time the fuzzing started + start_time: Duration, /// The corpus corpus: C, - // TODO use Duration - /// At what time the fuzzing started - start_time: u64, - /// Metadata stored for this state by one of the components - metadata: SerdeAnyMap, /// Feedbacks used to evaluate an input feedbacks: FT, - // Objective corpus - objective_corpus: OC, + // Solutions corpus + solutions: SC, /// Objective Feedbacks - objective_feedbacks: OFT, + objectives: OFT, + /// Metadata stored for this state by one of the components + metadata: SerdeAnyMap, phantom: PhantomData, } + +impl HasRand for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// The rand instance + #[inline] + fn rand(&self) -> &R { + &self.rand + } + + /// The rand instance (mut) + #[inline] + fn rand_mut(&mut self) -> &mut R { + &mut self.rand + } +} + + +impl HasCorpus for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// Returns the corpus + #[inline] + fn corpus(&self) -> &C { + &self.corpus + } + + /// Returns the mutable corpus + #[inline] + fn corpus_mut(&mut self) -> &mut C { + &mut self.corpus + } +} + +impl HasSolutions for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// Returns the solutions corpus + #[inline] + fn solutions(&self) -> &SC { + &self.solutions + } + + /// Returns the solutions corpus (mut) + #[inline] + fn solutions_mut(&mut self) -> &mut SC { + &mut self.solutions + } +} + +impl HasMetadata for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// Get all the metadata into an HashMap + #[inline] + fn metadata(&self) -> &SerdeAnyMap { + &self.metadata + } + + /// Get all the metadata into an HashMap (mutable) + #[inline] + fn metadata_mut(&mut self) -> &mut SerdeAnyMap { + &mut self.metadata + } +} + +impl HasFeedbacks for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// The feedbacks tuple + #[inline] + fn feedbacks(&self) -> &FT { + &self.feedbacks + } + + /// The feedbacks tuple (mut) + #[inline] + fn feedbacks_mut(&mut self) -> &mut FT { + &mut self.feedbacks + } +} + +impl HasObjectives for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// The objective feedbacks tuple + #[inline] + fn objectives(&self) -> &OFT { + &self.objectives + } + + /// The objective feedbacks tuple (mut) + #[inline] + fn objectives_mut(&mut self) -> &mut OFT { + &mut self.objectives + } +} + +impl HasExecutions for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// The executions counter + #[inline] + fn executions(&self) -> &usize { + &self.executions + } + + /// The executions counter (mut) + #[inline] + fn executions_mut(&mut self) -> &mut usize { + &mut self.executions + } +} + +impl HasStartTime for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// The starting time + #[inline] + fn start_time(&self) -> &Duration { + &self.start_time + } + + /// The starting time (mut) + #[inline] + fn start_time_mut(&mut self) -> &mut Duration { + &mut self.start_time + } +} + +impl IfInteresting for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// Evaluate if a set of observation channels has an interesting state + fn is_interesting( + &mut self, + input: &I, + observers: &OT, + exit_kind: ExitKind, + ) -> Result + where + OT: ObserversTuple, + { + Ok(self + .feedbacks_mut() + .is_interesting_all(input, observers, exit_kind)?) + } + + /// Adds this input to the corpus, if it's intersting, and return the index + #[inline] + fn add_if_interesting(&mut self, input: &I, fitness: u32) -> Result, Error> { + if fitness > 0 { + let testcase = self.testcase_with_feedbacks_metadata(input.clone(), fitness)?; + Ok(Some(self.corpus.add(testcase)?)) // TODO scheduler hook + } else { + self.discard_feedbacks_metadata(input)?; + Ok(None) + } + } +} + +impl Evaluator for State +where + C: Corpus, + I: Input, + R: Rand, + FT: FeedbacksTuple, + SC: Corpus, + OFT: FeedbacksTuple, +{ + /// Process one input, adding to the respective corpuses if needed and firing the right events + #[inline] + fn evaluate_input( + &mut self, + // TODO probably we can take a ref to input and pass a cloned one to add_if_interesting + input: I, + executor: &mut E, + manager: &mut EM, + ) -> Result + where + E: Executor + HasObservers, + OT: ObserversTuple, + C: Corpus, + EM: EventManager, + { + let (fitness, is_solution) = self.execute_input(&input, executor, manager)?; + let observers = executor.observers(); + + if is_solution { + // If the input is a solution, add it to the respective corpus + self.solutions_mut().add(Testcase::new(input.clone()))?; + } + + if let idx = Some(self.add_if_interesting(&input, fitness)?) { + let observers_buf = manager.serialize_observers(observers)?; + manager.fire( + self, + Event::NewTestcase { + input: input, + observers_buf, + corpus_size: self.corpus().count() + 1, + client_config: "TODO".into(), + time: crate::utils::current_time(), + executions: *self.executions(), + }, + )?; + } + + Ok(fitness) + } +} + + #[cfg(feature = "std")] -impl State +impl State where C: Corpus, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + SC: Corpus, OFT: FeedbacksTuple, { pub fn load_from_directory( @@ -133,12 +508,12 @@ where println!("Loading file {:?} ...", &path); let bytes = fs::read(&path)?; let input = BytesInput::new(bytes); - let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?; - if self.add_if_interesting(input, fitness)?.is_none() { + let (fitness, is_solution) = self.execute_input(&input, executor, manager)?; + if self.add_if_interesting(&input, fitness)?.is_none() { println!("File {:?} was not interesting, skipped.", &path); } - if obj_fitness > 0 { - println!("File {:?} is an objective, however will be not added as an initial testcase.", &path); + if is_solution { + println!("File {:?} is a solution, however will be not considered as it is an initial testcase.", &path); } } else if attr.is_dir() { self.load_from_directory(executor, manager, &path)?; @@ -176,159 +551,23 @@ where } } -impl HasRand for State + +impl State where C: Corpus, I: Input, R: Rand, FT: FeedbacksTuple, - OC: Corpus, + SC: Corpus, OFT: FeedbacksTuple, { - /// The rand instance - fn rand(&self) -> &R { - &self.rand - } - - /// The rand instance (mut) - fn rand_mut(&mut self) -> &mut R { - &mut self.rand - } -} - - -impl HasCorpus for State -where - C: Corpus, - I: Input, - R: Rand, - FT: FeedbacksTuple, - OC: Corpus, - OFT: FeedbacksTuple, -{ - /// Returns the corpus - fn corpus(&self) -> &C { - &self.corpus - } - - /// Returns the mutable corpus - fn corpus_mut(&mut self) -> &mut C { - &mut self.corpus - } -} - -/// Trait for elements offering metadata -impl HasMetadata for State -where - C: Corpus, - I: Input, - R: Rand, - FT: FeedbacksTuple, - OC: Corpus, - OFT: FeedbacksTuple, -{ - /// Get all the metadata into an HashMap - #[inline] - fn metadata(&self) -> &SerdeAnyMap { - &self.metadata - } - - /// Get all the metadata into an HashMap (mutable) - #[inline] - fn metadata_mut(&mut self) -> &mut SerdeAnyMap { - &mut self.metadata - } -} - -impl State -where - C: Corpus, - I: Input, - R: Rand, - FT: FeedbacksTuple, - OC: Corpus, - OFT: FeedbacksTuple, -{ - /// Get executions - #[inline] - pub fn executions(&self) -> usize { - self.executions - } - - /// Set executions - #[inline] - pub fn set_executions(&mut self, executions: usize) { - self.executions = executions - } - - #[inline] - pub fn start_time(&self) -> u64 { - self.start_time - } - #[inline] - pub fn set_start_time(&mut self, ms: u64) { - self.start_time = ms - } - - /// Returns vector of feebacks - #[inline] - pub fn feedbacks(&self) -> &FT { - &self.feedbacks - } - - /// Returns vector of feebacks (mutable) - #[inline] - pub fn feedbacks_mut(&mut self) -> &mut FT { - &mut self.feedbacks - } - - /// Returns vector of objective feebacks - #[inline] - pub fn objective_feedbacks(&self) -> &OFT { - &self.objective_feedbacks - } - - /// Returns vector of objective feebacks (mutable) - #[inline] - pub fn objective_feedbacks_mut(&mut self) -> &mut OFT { - &mut self.objective_feedbacks - } - - /// Returns the objective corpus - #[inline] - pub fn objective_corpus(&self) -> &OC { - &self.objective_corpus - } - - /// Returns the mutable objective corpus - #[inline] - pub fn objective_corpus_mut(&mut self) -> &mut OC { - &mut self.objective_corpus - } - - // TODO move some of these, like evaluate_input, to FuzzingEngine - #[inline] - pub fn is_interesting( - &mut self, - input: &I, - observers: &OT, - exit_kind: ExitKind, - ) -> Result - where - OT: ObserversTuple, - { - Ok(self - .feedbacks_mut() - .is_interesting_all(input, observers, exit_kind)?) - } - /// Runs the input and triggers observers and feedback - pub fn evaluate_input( + pub fn execute_input( &mut self, input: &I, executor: &mut E, event_mgr: &mut EM, - ) -> Result<(u32, u32), Error> + ) -> Result<(u32, bool), Error> where E: Executor + HasObservers, OT: ObserversTuple, @@ -341,121 +580,18 @@ where let exit_kind = executor.run_target(input)?; executor.post_exec(&self, event_mgr, input)?; - self.set_executions(self.executions() + 1); + *self.executions_mut() += 1; executor.post_exec_observers()?; let observers = executor.observers(); - let objective_fitness = - self.objective_feedbacks - .is_interesting_all(&input, observers, exit_kind.clone())?; + let fitness = self .feedbacks_mut() .is_interesting_all(&input, observers, exit_kind)?; - Ok((fitness, objective_fitness)) - } + + let is_solution = self.objectives_mut().is_interesting_all(&input, observers, exit_kind.clone())? > 0; - /// Resets all current feedbacks - #[inline] - pub fn discard_input(&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] - pub fn input_to_testcase(&mut self, input: I, fitness: u32) -> Result, Error> { - let mut testcase = Testcase::new(input); - testcase.set_fitness(fitness); - self.feedbacks_mut().append_metadata_all(&mut testcase)?; - Ok(testcase) - } - - /// Create a testcase from this input, if it's intersting - #[inline] - pub fn testcase_if_interesting( - &mut self, - input: I, - fitness: u32, - ) -> Result>, Error> { - if fitness > 0 { - Ok(Some(self.input_to_testcase(input, fitness)?)) - } else { - self.discard_input(&input)?; - Ok(None) - } - } - - /// Adds this input to the corpus, if it's intersting - #[inline] - pub fn add_if_interesting(&mut self, input: I, fitness: u32) -> Result, Error> - where - C: Corpus, - { - if fitness > 0 { - let testcase = self.input_to_testcase(input, fitness)?; - Ok(Some(C::add(self, testcase)?)) - } else { - self.discard_input(&input)?; - Ok(None) - } - } - - /// Adds this input to the objective corpus, if it's an objective - #[inline] - pub fn add_if_objective(&mut self, input: I, fitness: u32) -> Result, Error> - where - C: Corpus, - { - if fitness > 0 { - let testcase = self.input_to_testcase(input, fitness)?; - Ok(Some(self.objective_corpus.add(testcase))) - } else { - self.discard_input(&input)?; - Ok(None) - } - } - - /// Process one input, adding to the respective corpuses if needed and firing the right events - #[inline] - pub fn process_input( - &mut self, - // TODO probably we can take a ref to input and pass a cloned one to add_if_interesting - input: I, - executor: &mut E, - manager: &mut EM, - ) -> Result - where - E: Executor + HasObservers, - OT: ObserversTuple, - C: Corpus, - EM: EventManager, - { - let (fitness, obj_fitness) = self.evaluate_input(&input, executor, manager)?; - let observers = executor.observers(); - - if obj_fitness > 0 { - self.add_if_objective(input.clone(), obj_fitness)?; - } - - if fitness > 0 { - let observers_buf = manager.serialize_observers(observers)?; - manager.fire( - self, - Event::NewTestcase { - input: input.clone(), - observers_buf, - corpus_size: self.corpus().count() + 1, - client_config: "TODO".into(), - time: crate::utils::current_time(), - executions: self.executions(), - }, - )?; - self.add_if_interesting(input, fitness)?; - } else { - self.discard_input(&input)?; - } - - Ok(fitness) + Ok((fitness, is_solution)) } pub fn generate_initial_inputs( @@ -475,8 +611,8 @@ where { let mut added = 0; for _ in 0..num { - let input = generator.generate(rand)?; - let fitness = self.process_input(input, executor, manager)?; + let input = generator.generate(self.rand_mut())?; + let fitness = self.evaluate_input(input, executor, manager)?; if fitness > 0 { added += 1; } @@ -493,15 +629,16 @@ where Ok(()) } - pub fn new(corpus: C, feedbacks: FT, objective_corpus: OC, objective_feedbacks: OFT) -> Self { + pub fn new(rand: R, corpus: C, feedbacks: FT, solutions: SC, objectives: OFT) -> Self { Self { - corpus, + rand, executions: 0, - start_time: current_milliseconds(), + start_time: Duration::from_millis(0), metadata: SerdeAnyMap::default(), - feedbacks: feedbacks, - objective_corpus: objective_corpus, - objective_feedbacks: objective_feedbacks, + corpus, + feedbacks, + solutions, + objectives, phantom: PhantomData, } } From a3b30a28699216c1d97b2437c4c74291ccdfe713 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 19 Feb 2021 16:10:30 +0100 Subject: [PATCH 04/10] save work and go to the grocery shop --- libafl/src/mutators/mod.rs | 6 ++++-- libafl/src/mutators/mutations.rs | 12 +++++++----- libafl/src/mutators/scheduled.rs | 3 ++- libafl/src/stages/mod.rs | 24 ++++++++++++++---------- libafl/src/stages/mutational.rs | 12 +++++++----- 5 files changed, 34 insertions(+), 23 deletions(-) diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 8498b700ea..3bbd89d98b 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -22,16 +22,18 @@ where I: Input, { /// Mutate a given input - fn mutate( + fn mutate( &mut self, + fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32, ) -> Result<(), Error>; /// Post-process given the outcome of the execution - fn post_exec( + fn post_exec( &mut 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 19f72ebeae..8cd1b52bc0 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -27,21 +27,21 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = - fn(&mut M, &mut S, &mut I) -> Result; +pub type MutationFunction = + fn(&mut M, &F, &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 @@ -939,6 +939,7 @@ pub fn read_tokens_file(f: &str, tokens: &mut Vec>) -> Result( &mut self, + fuzzer: &F, state: &mut S, input: &mut I, _stage_idx: i32, diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index dda5bb1ed0..940b7d7c71 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -17,10 +17,11 @@ where I: Input { /// Run the stage - fn perform( + fn perform( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -33,10 +34,11 @@ pub trait StagesTuple where I: Input { - fn perform_all( + fn perform_all( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -49,10 +51,11 @@ impl StagesTuple for () where I: Input { - fn perform_all( + fn perform_all( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -70,10 +73,11 @@ where Tail: StagesTuple + TupleList, I: Input { - fn perform_all( + fn perform_all( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -81,7 +85,7 @@ where EM: EventManager, E: Executor { - self.0.perform(executor, state, manager, corpus_idx)?; - self.1 .perform_all(executor, state, manager, corpus_idx) + self.0.perform(fuzzer, state, executor, manager, corpus_idx)?; + self.1 .perform_all(fuzzer, state, executor, manager, corpus_idx) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 2e292912ce..c45574446d 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -33,10 +33,11 @@ where fn iterations(&mut self, state: &mut S) -> usize; /// Runs this (mutational) stage for the given testcase - fn perform_mutational( + fn perform_mutational( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -111,10 +112,11 @@ where I: Input, { #[inline] - fn perform( + fn perform( &self, - executor: &mut E, + fuzzer: &F, state: &mut S, + executor: &mut E, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> @@ -124,7 +126,7 @@ where S: HasCorpus + Evaluator, C: Corpus { - self.perform_mutational(executor, state, manager, corpus_idx) + self.perform_mutational(fuzzer, state, executor, manager, corpus_idx) } } From 93947c44cfa771ce757fd157c4f4397195ca4f94 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sun, 21 Feb 2021 14:34:51 +0100 Subject: [PATCH 05/10] executor fix --- libafl/src/executors/inprocess.rs | 132 +++++++++++------------------- 1 file changed, 50 insertions(+), 82 deletions(-) diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 2fbe02ad2e..76a1d72a9b 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -14,7 +14,7 @@ use crate::{ feedbacks::FeedbacksTuple, inputs::{HasTargetBytes, Input}, observers::ObserversTuple, - state::State, + state::{HasObjectives, HasSolutions}, utils::Rand, Error, }; @@ -54,35 +54,20 @@ where OT: ObserversTuple, { #[inline] - fn pre_exec( - &mut self, - state: &mut S, - event_mgr: &mut EM, - input: &I, - ) -> Result<(), Error> + fn pre_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> where EM: EventManager, { #[cfg(unix)] #[cfg(feature = "std")] unsafe { - set_oncrash_ptrs( - state, - event_mgr, - self.observers(), - input, - ); + set_oncrash_ptrs(state, event_mgr, self.observers(), input); } Ok(()) } #[inline] - fn post_exec( - &mut self, - _state: &S, - _event_mgr: &mut EM, - _input: &I, - ) -> Result<(), Error> + fn post_exec(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> where EM: EventManager, { @@ -139,25 +124,24 @@ 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, - _state: &mut State, + _state: &mut S, _event_mgr: &mut EM, ) -> Self where - R: Rand, - FT: FeedbacksTuple, + EM: EventManager, OC: Corpus, OFT: FeedbacksTuple, - C: Corpus, - EM: EventManager, + S: HasObjectives + HasSolutions, + R: Rand, { #[cfg(feature = "std")] #[cfg(unix)] unsafe { - setup_crash_handlers::(); + setup_crash_handlers::(); } Self { @@ -188,13 +172,13 @@ pub mod unix_signals { }; use crate::{ - corpus::Corpus, + corpus::{Corpus, Testcase}, events::{Event, EventManager}, executors::ExitKind, feedbacks::FeedbacksTuple, inputs::Input, observers::ObserversTuple, - state::State, + state::{HasObjectives, HasSolutions}, utils::Rand, }; /// Let's get 8 mb for now. @@ -211,17 +195,16 @@ 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( + unsafe fn inmem_handle_crash( _sig: c_int, info: siginfo_t, _void: c_void, ) where EM: EventManager, - C: Corpus, OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, - FT: FeedbacksTuple, + S: HasObjectives + HasSolutions, I: Input, R: Rand, { @@ -236,7 +219,6 @@ pub mod unix_signals { Ok(maps) => println!("maps:\n{}", maps), Err(e) => println!("Couldn't load mappings: {:?}", e), }; - #[cfg(feature = "std")] { println!("Type QUIT to restart the child"); @@ -258,30 +240,23 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); // Make sure we don't crash in the crash handler forever. CURRENT_INPUT_PTR = ptr::null(); - let state = (STATE_PTR as *mut State) - .as_mut() - .unwrap(); + let state = (STATE_PTR as *mut S).as_mut().unwrap(); let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap(); let observers = (OBSERVERS_PTR as *const OT).as_ref().unwrap(); let obj_fitness = state - .objective_feedbacks_mut() + .objectives_mut() .is_interesting_all(&input, observers, ExitKind::Crash) - .expect("In crash handler objective feedbacks failure.".into()); + .expect("In crash handler objectives failure.".into()); if obj_fitness > 0 { - if !state - .add_if_objective(input.clone(), obj_fitness) - .expect("In crash handler objective corpus add failure.".into()) - .is_none() - { - mgr.fire( - state, - Event::Objective { - objective_size: state.objective_corpus().count(), - }, - ) - .expect(&format!("Could not send timeouting input {:?}", input)); - } + state.solutions_mut().add(Testcase::new(*input)); + mgr.fire( + state, + Event::Objective { + objective_size: state.solutions().count(), + }, + ) + .expect("Could not send crashing input".into()); } mgr.on_restart(state).unwrap(); @@ -293,17 +268,16 @@ pub mod unix_signals { std::process::exit(1); } - unsafe fn inmem_handle_timeout( + unsafe fn inmem_handle_timeout( _sig: c_int, - _info: siginfo_t, + info: siginfo_t, _void: c_void, ) where EM: EventManager, - C: Corpus, + OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, + S: HasObjectives + HasSolutions, I: Input, R: Rand, { @@ -319,34 +293,31 @@ pub mod unix_signals { let input = (CURRENT_INPUT_PTR as *const I).as_ref().unwrap(); // Make sure we don't crash in the crash handler forever. CURRENT_INPUT_PTR = ptr::null(); - let state = (STATE_PTR as *mut State) - .as_mut() - .unwrap(); + let state = (STATE_PTR as *mut S).as_mut().unwrap(); let mgr = (EVENT_MGR_PTR as *mut EM).as_mut().unwrap(); let observers = (OBSERVERS_PTR as *const OT).as_ref().unwrap(); let obj_fitness = state - .objective_feedbacks_mut() - .is_interesting_all(&input, observers, ExitKind::Timeout) - .expect("In timeout handler objective feedbacks failure.".into()); + .objectives_mut() + .is_interesting_all(&input, observers, ExitKind::Crash) + .expect("In timeout handler objectives failure.".into()); if obj_fitness > 0 { - if !state - .add_if_objective(input.clone(), obj_fitness) - .expect("In timeout handler objective corpus add failure.".into()) - .is_none() - { - mgr.fire( - state, - Event::Objective { - objective_size: state.objective_corpus().count(), - }, - ) - .expect(&format!("Could not send timeouting input {:?}", input)); - } + state.solutions_mut().add(Testcase::new(*input)); + mgr.fire( + state, + Event::Objective { + objective_size: state.solutions().count(), + }, + ) + .expect("Could not send timeouting input".into()); } mgr.on_restart(state).unwrap(); + println!("Waiting for broker..."); + mgr.await_restart_safe(); + println!("Bye!"); + mgr.await_restart_safe(); std::process::exit(1); @@ -373,14 +344,13 @@ pub mod unix_signals { OBSERVERS_PTR = ptr::null(); } - pub unsafe fn setup_crash_handlers() + pub unsafe fn setup_crash_handlers() where EM: EventManager, - C: Corpus, + OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, - OT: ObserversTuple, - FT: FeedbacksTuple, + S: HasObjectives + HasSolutions, I: Input, R: Rand, { @@ -399,8 +369,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"), @@ -414,8 +383,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"); } From 158564597262e29e66d600612aa873811c9d81c4 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sun, 21 Feb 2021 16:10:57 +0100 Subject: [PATCH 06/10] fuck you rust --- libafl/benches/hash_speeds.rs | 2 +- libafl/src/corpus/mod.rs | 40 +++++++---- libafl/src/events/llmp.rs | 54 ++++---------- libafl/src/events/logger.rs | 32 +++------ libafl/src/events/mod.rs | 44 +++--------- libafl/src/fuzzer.rs | 56 +++++++-------- libafl/src/mutators/mutations.rs | 120 ++++++++++++++++--------------- libafl/src/mutators/scheduled.rs | 85 ++++++++++------------ libafl/src/stages/mod.rs | 66 ++++++----------- libafl/src/stages/mutational.rs | 17 ++--- libafl/src/state/mod.rs | 33 +++++---- 11 files changed, 232 insertions(+), 317 deletions(-) diff --git a/libafl/benches/hash_speeds.rs b/libafl/benches/hash_speeds.rs index 20d22f5748..1e2b016c9f 100644 --- a/libafl/benches/hash_speeds.rs +++ b/libafl/benches/hash_speeds.rs @@ -6,8 +6,8 @@ use std::hash::Hasher; use xxhash_rust::const_xxh3; use xxhash_rust::xxh3; -use libafl::utils::{Rand, StdRand}; use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use libafl::utils::{Rand, StdRand}; fn criterion_benchmark(c: &mut Criterion) { let mut rand = StdRand::new(0); diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 126c2b2898..02493aa84b 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -3,9 +3,9 @@ pub mod testcase; pub use testcase::Testcase; -use alloc::{vec::Vec}; -use core::{cell::RefCell}; -use serde::{Serialize, Deserialize}; +use alloc::vec::Vec; +use core::cell::RefCell; +use serde::{Deserialize, Serialize}; use crate::{ inputs::Input, @@ -36,36 +36,50 @@ where } pub trait CorpusScheduler { - /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> + fn on_add( + &self, + state: &mut S, + idx: usize, + testcase: &Testcase, + ) -> Result<(), Error> where S: HasCorpus + HasRand, C: Corpus, I: Input, - R: Rand + R: Rand, { Ok(()) } /// Replaces the testcase at the given idx - fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> + fn on_replace( + &self, + state: &mut S, + idx: usize, + testcase: &Testcase, + ) -> Result<(), Error> where S: HasCorpus + HasRand, C: Corpus, I: Input, - R: Rand + R: Rand, { Ok(()) } /// Removes an entry from the corpus, returning it if it was present. - fn on_remove(&self, state: &mut S, idx: usize, testcase: &Option>) -> Result<(), Error> + fn on_remove( + &self, + state: &mut S, + idx: usize, + testcase: &Option>, + ) -> Result<(), Error> where S: HasCorpus + HasRand, C: Corpus, I: Input, - R: Rand + R: Rand, { Ok(()) } @@ -78,9 +92,9 @@ pub trait CorpusScheduler { C: Corpus, I: Input, R: Rand; - } +/* pub struct RandCorpusScheduler {} impl CorpusScheduler for RandCorpusScheduler { @@ -90,7 +104,7 @@ impl CorpusScheduler for RandCorpusScheduler { S: HasCorpus + HasRand, C: Corpus, I: Input, - R: Rand + R: Rand, { if state.corpus().count() == 0 { Err(Error::Empty("No entries in corpus".to_owned())) @@ -101,6 +115,7 @@ impl CorpusScheduler for RandCorpusScheduler { } } } +*/ #[derive(Default, Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] @@ -115,7 +130,6 @@ impl Corpus for InMemoryCorpus where I: Input, { - /// Returns the number of elements #[inline] fn count(&self) -> usize { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index fe46d05054..27f6078ab3 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -1,7 +1,7 @@ use crate::bolts::llmp::LlmpSender; use alloc::{string::ToString, vec::Vec}; use core::{marker::PhantomData, time::Duration}; -use serde::{Serialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Serialize}; #[cfg(feature = "std")] use crate::bolts::llmp::LlmpReceiver; @@ -22,7 +22,7 @@ use crate::{ executors::{Executor, HasObservers}, inputs::Input, observers::ObserversTuple, - state::{IfInteresting}, + state::IfInteresting, stats::Stats, Error, }; @@ -258,7 +258,7 @@ where where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting + S: IfInteresting, { match event { Event::NewTestcase { @@ -293,7 +293,7 @@ where } } -impl EventManager for LlmpEventManager +impl EventManager for LlmpEventManager where I: Input, SH: ShMem, @@ -311,15 +311,11 @@ where } } - fn process( - &mut self, - state: &mut S, - executor: &mut E, - ) -> Result + fn process(&mut self, state: &mut S, executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting + S: IfInteresting, { // TODO: Get around local event copy by moving handle_in_client let mut events = vec![]; @@ -348,11 +344,7 @@ where Ok(count) } - fn fire( - &mut self, - _state: &mut S, - event: Event, - ) -> Result<(), Error> { + fn fire(&mut self, _state: &mut S, event: Event) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; Ok(()) @@ -407,7 +399,7 @@ where sender: LlmpSender, } -impl EventManager for LlmpRestartingEventManager +impl EventManager for LlmpRestartingEventManager where I: Input, SH: ShMem, @@ -421,10 +413,7 @@ where } /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. - fn on_restart( - &mut self, - state: &mut S, - ) -> Result<(), Error> + fn on_restart(&mut self, state: &mut S) -> Result<(), Error> where S: Serialize, { @@ -435,24 +424,16 @@ where .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) } - fn process( - &mut self, - state: &mut S, - executor: &mut E, - ) -> Result + fn process(&mut self, state: &mut S, executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting + S: IfInteresting, { self.llmp_mgr.process(state, executor) } - fn fire( - &mut self, - state: &mut S, - event: Event, - ) -> Result<(), Error> { + fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error> { // Check if we are going to crash in the event, in which case we store our current state for the next runner self.llmp_mgr.fire(state, event) } @@ -493,13 +474,7 @@ pub fn setup_restarting_mgr( //mgr: &mut LlmpEventManager, stats: ST, broker_port: u16, -) -> Result< - ( - Option, - LlmpRestartingEventManager, - ), - Error, -> +) -> Result<(Option, LlmpRestartingEventManager), Error> where I: Input, S: DeserializeOwned, @@ -562,8 +537,7 @@ where // Restoring from a previous run, deserialize state and corpus. Some((_sender, _tag, msg)) => { println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); - let (state, mgr): (S, LlmpEventManager) = - deserialize_state_mgr(&msg)?; + let (state, mgr): (S, LlmpEventManager) = deserialize_state_mgr(&msg)?; (Some(state), LlmpRestartingEventManager::new(mgr, sender)) } diff --git a/libafl/src/events/logger.rs b/libafl/src/events/logger.rs index e96f5d3ac0..0a37f9b8f2 100644 --- a/libafl/src/events/logger.rs +++ b/libafl/src/events/logger.rs @@ -1,10 +1,10 @@ use alloc::{string::ToString, vec::Vec}; +use core::marker::PhantomData; #[cfg(feature = "std")] #[cfg(unix)] use crate::{ events::{BrokerEventResult, Event, EventManager}, - executors::{Executor}, inputs::Input, stats::Stats, Error, @@ -12,7 +12,7 @@ use crate::{ /// A simple, single-threaded event manager that just logs #[derive(Clone, Debug)] -pub struct LoggerEventManager +pub struct LoggerEventManager where I: Input, ST: Stats, //CE: CustomEvent, @@ -21,21 +21,15 @@ where stats: ST, /// The events that happened since the last handle_in_broker events: Vec>, + phantom: PhantomData<(E, S)>, } -impl EventManager for LoggerEventManager +impl EventManager for LoggerEventManager where I: Input, ST: Stats, //CE: CustomEvent, { - fn process( - &mut self, - state: &mut S, - _executor: &mut E, - ) -> Result - where - E: Executor - { + fn process(&mut self, state: &mut S, _executor: &mut E) -> Result { let count = self.events.len(); while self.events.len() > 0 { let event = self.events.pop().unwrap(); @@ -44,12 +38,7 @@ where Ok(count) } - fn fire( - &mut self, - _state: &mut S, - event: Event, - ) -> Result<(), Error> - { + fn fire(&mut self, _state: &mut S, event: Event) -> Result<(), Error> { match Self::handle_in_broker(&mut self.stats, &event)? { BrokerEventResult::Forward => self.events.push(event), BrokerEventResult::Handled => (), @@ -58,7 +47,7 @@ where } } -impl LoggerEventManager +impl LoggerEventManager where I: Input, ST: Stats, //TODO CE: CustomEvent, @@ -67,6 +56,7 @@ where Self { stats: stats, events: vec![], + phantom: PhantomData, } } @@ -115,11 +105,7 @@ where } // Handle arriving events in the client - fn handle_in_client( - &mut self, - _state: &mut S, - event: Event, - ) -> Result<(), Error> { + fn handle_in_client(&mut self, _state: &mut S, event: Event) -> Result<(), Error> { match event { _ => Err(Error::Unknown(format!( "Received illegal message that message should not have arrived: {:?}.", diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 1aa4f00440..a1c03ff11f 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -9,10 +9,7 @@ use core::{fmt, marker::PhantomData, time::Duration}; use serde::{Deserialize, Serialize}; use crate::{ - executors::{Executor}, - inputs::Input, - observers::ObserversTuple, - Error, + executors::Executor, inputs::Input, observers::ObserversTuple, state::IfInteresting, Error, }; /// The log event severity @@ -149,7 +146,7 @@ where /// EventManager is the main communications hub. /// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager` -pub trait EventManager +pub trait EventManager where I: Input, { @@ -158,13 +155,7 @@ where /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process( - &mut self, - state: &mut S, - executor: &mut E, - ) -> Result - where - E: Executor; + fn process(&mut self, state: &mut S, executor: &mut E) -> Result; /// Serialize all observers for this type and manager fn serialize_observers(&mut self, observers: &OT) -> Result, Error> @@ -184,10 +175,7 @@ where /// For restarting event managers, implement a way to forward state to their next peers. #[inline] - fn on_restart( - &mut self, - _state: &mut S, - ) -> Result<(), Error> { + fn on_restart(&mut self, _state: &mut S) -> Result<(), Error> { Ok(()) } @@ -196,38 +184,26 @@ where fn await_restart_safe(&mut self) {} /// Send off an event to the broker - fn fire( - &mut self, - state: &mut S, - event: Event, - ) -> Result<(), Error>; + fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error>; } /// An eventmgr for tests, and as placeholder if you really don't need an event manager. #[derive(Copy, Clone, Debug)] -pub struct NopEventManager { - phantom: PhantomData, +pub struct NopEventManager { + phantom: PhantomData<(E, I, S)>, } -impl EventManager for NopEventManager +impl EventManager for NopEventManager where I: Input, { - fn process( - &mut self, - _state: &mut S, - _executor: &mut E, - ) -> Result + fn process(&mut self, _state: &mut S, _executor: &mut E) -> Result where E: Executor, { Ok(0) } - fn fire( - &mut self, - _state: &mut S, - _event: Event, - ) -> Result<(), Error> { + fn fire(&mut self, _state: &mut S, _event: Event) -> Result<(), Error> { Ok(()) } } diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index e4d924749d..88f5960c94 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -1,21 +1,20 @@ -use core::{marker::PhantomData}; - use crate::{ - corpus::{CorpusScheduler, Corpus}, + corpus::{Corpus, CorpusScheduler}, events::{Event, EventManager}, - executors::{Executor}, + executors::Executor, inputs::Input, stages::StagesTuple, - state::{HasRand, HasCorpus, HasExecutions}, - utils::{Rand, current_milliseconds, current_time}, - Error + state::{HasCorpus, HasExecutions, HasRand}, + utils::{current_milliseconds, current_time, Rand}, + Error, }; +use core::marker::PhantomData; /// Holds a set of stages pub trait HasStages where ST: StagesTuple, - I: Input + I: Input, { fn stages(&self) -> &ST; @@ -37,12 +36,12 @@ pub trait Fuzzer: HasCorpusScheduler + HasStages where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { fn fuzz_one( - &mut self, - executor: &mut E, + &self, state: &mut S, + executor: &mut E, manager: &mut EM, ) -> Result where @@ -50,9 +49,9 @@ where E: Executor; fn fuzz_loop( - &mut self, - executor: &mut E, + &self, state: &mut S, + executor: &mut E, manager: &mut EM, ) -> Result where @@ -66,18 +65,18 @@ pub struct StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { scheduler: CS, stages: ST, - phantom: PhantomData + phantom: PhantomData, } impl HasStages for StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { fn stages(&self) -> &ST { &self.stages @@ -92,7 +91,7 @@ impl HasCorpusScheduler for StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { fn scheduler(&self) -> &CS { &self.scheduler @@ -107,12 +106,12 @@ impl Fuzzer for StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { fn fuzz_one( - &mut self, - executor: &mut E, + &self, state: &mut S, + executor: &mut E, manager: &mut EM, ) -> Result where @@ -120,21 +119,21 @@ where E: Executor, S: HasCorpus + HasRand, C: Corpus, - R: Rand + R: Rand, { let idx = self.scheduler().next(state)?; self.stages() - .perform_all(executor, state, manager, idx)?; + .perform_all(self, state, executor, manager, idx)?; manager.process(state, executor)?; Ok(idx) } fn fuzz_loop( - &mut self, - executor: &mut E, + &self, state: &mut S, + executor: &mut E, manager: &mut EM, ) -> Result where @@ -142,11 +141,11 @@ where E: Executor, S: HasCorpus + HasRand + HasExecutions, C: Corpus, - R: Rand + R: Rand, { let mut last = current_milliseconds(); loop { - self.fuzz_one(executor, state, manager)?; + self.fuzz_one(state, executor, manager)?; let cur = current_milliseconds(); if cur - last > 60 * 100 { last = cur; @@ -163,18 +162,17 @@ where } } - impl StdFuzzer where CS: CorpusScheduler, ST: StagesTuple, - I: Input + I: Input, { pub fn new(scheduler: CS, stages: ST) -> Self { Self { scheduler: scheduler, stages: stages, - phantom: PhantomData + phantom: PhantomData, } } } diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 8cd1b52bc0..2813a1ebc8 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -1,8 +1,8 @@ use crate::{ - inputs::{HasBytesVec, Input}, corpus::Corpus, + inputs::{HasBytesVec, Input}, mutators::*, - state::{HasRand, HasCorpus}, + state::{HasCorpus, HasRand}, utils::Rand, Error, }; @@ -27,21 +27,21 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = +pub type MutationFunction = fn(&mut M, &F, &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 @@ -87,7 +87,6 @@ fn buffer_set(data: &mut [u8], from: usize, len: usize, val: u8) { } } - const ARITH_MAX: u64 = 35; const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; @@ -125,15 +124,16 @@ const INTERESTING_32: [i32; 27] = [ ]; /// Bitflip mutation for inputs with a bytes vector -pub fn mutation_bitflip( +pub fn mutation_bitflip( _: &mut M, + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result where I: Input + HasBytesVec, S: HasRand, - R: Rand + R: Rand, { if input.bytes().len() == 0 { Ok(MutationResult::Skipped) @@ -147,9 +147,9 @@ where } } -pub fn mutation_byteflip( +pub fn mutation_byteflip( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -170,9 +170,9 @@ where } } -pub fn mutation_byteinc( +pub fn mutation_byteinc( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -194,9 +194,9 @@ where } } -pub fn mutation_bytedec( +pub fn mutation_bytedec( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -218,9 +218,9 @@ where } } -pub fn mutation_byteneg( +pub fn mutation_byteneg( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -241,9 +241,9 @@ where } } -pub fn mutation_byterand( +pub fn mutation_byterand( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -264,9 +264,9 @@ where } } -pub fn mutation_byteadd( +pub fn mutation_byteadd( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -292,9 +292,9 @@ where } } -pub fn mutation_wordadd( +pub fn mutation_wordadd( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -322,9 +322,9 @@ where } } -pub fn mutation_dwordadd( +pub fn mutation_dwordadd( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -352,9 +352,9 @@ where } } -pub fn mutation_qwordadd( +pub fn mutation_qwordadd( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -382,9 +382,9 @@ where } } -pub fn mutation_byteinteresting( +pub fn mutation_byteinteresting( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -406,9 +406,9 @@ where } } -pub fn mutation_wordinteresting( +pub fn mutation_wordinteresting( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -421,7 +421,8 @@ where Ok(MutationResult::Skipped) } else { let idx = state.rand_mut().below(input.bytes().len() as u64 - 1) as usize; - let val = INTERESTING_16[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u16; + let val = + INTERESTING_16[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u16; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u16; @@ -435,9 +436,9 @@ where } } -pub fn mutation_dwordinteresting( +pub fn mutation_dwordinteresting( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -450,7 +451,8 @@ where Ok(MutationResult::Skipped) } else { let idx = state.rand_mut().below(input.bytes().len() as u64 - 3) as usize; - let val = INTERESTING_32[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u32; + let val = + INTERESTING_32[state.rand_mut().below(INTERESTING_8.len() as u64) as usize] as u32; unsafe { // Moar speed, no bound check let ptr = input.bytes_mut().get_unchecked_mut(idx) as *mut _ as *mut u32; @@ -464,9 +466,9 @@ where } } -pub fn mutation_bytesdelete( +pub fn mutation_bytesdelete( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -487,9 +489,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesexpand( - // TODO: max_size instead of mutator? +pub fn mutation_bytesexpand( mutator: &mut M, + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -517,8 +519,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesinsert( +pub fn mutation_bytesinsert( mutator: &mut M, + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -549,9 +552,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandinsert( +pub fn mutation_bytesrandinsert( mutator: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -582,9 +585,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesset( +pub fn mutation_bytesset( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -607,9 +610,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesrandset( +pub fn mutation_bytesrandset( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -632,9 +635,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytescopy( +pub fn mutation_bytescopy( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -657,9 +660,9 @@ where Ok(MutationResult::Mutated) } -pub fn mutation_bytesswap( +pub fn mutation_bytesswap( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -685,8 +688,9 @@ where } /// Crossover insert mutation -pub fn mutation_crossover_insert( +pub fn mutation_crossover_insert( mutator: &mut M, + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -733,9 +737,9 @@ where } /// Crossover replace mutation -pub fn mutation_crossover_replace( +pub fn mutation_crossover_replace( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -787,9 +791,9 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { } /// Splicing mutation from AFL -pub fn mutation_splice( +pub fn mutation_splice( _: &mut M, - + fuzzer: &F, state: &mut S, input: &mut I, ) -> Result @@ -821,7 +825,9 @@ where counter += 1; }; - let split_at = state.rand_mut().between(first_diff as u64, last_diff as u64) as usize; + let split_at = state + .rand_mut() + .between(first_diff as u64, last_diff as u64) as usize; input .bytes_mut() .splice(split_at.., other.bytes()[split_at..].iter().cloned()); @@ -1056,4 +1062,4 @@ token2="B" */ } } -*/ \ No newline at end of file +*/ diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index b962da9f98..a40e84329e 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -1,13 +1,13 @@ use crate::inputs::HasBytesVec; use alloc::vec::Vec; -use core::{fmt, default::Default, marker::PhantomData}; +use core::{default::Default, fmt, marker::PhantomData}; use fmt::Debug; use crate::{ - inputs::{Input}, - mutators::{Mutator, HasMaxSize, DEFAULT_MAX_SIZE}, - state::{HasRand, HasCorpus, HasMetadata}, corpus::Corpus, + inputs::Input, + mutators::{HasMaxSize, Mutator, DEFAULT_MAX_SIZE}, + state::{HasCorpus, HasMetadata, HasRand}, utils::Rand, Error, }; @@ -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, { @@ -34,7 +34,7 @@ where /// New default implementation for mutate /// Implementations must forward mutate() to this method - fn scheduled_mutate( + fn scheduled_mutate( &mut self, fuzzer: &F, state: &mut S, @@ -44,27 +44,24 @@ where 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, state, input)?; + self.mutation_by_idx(idx)(self, fuzzer, state, input)?; } Ok(()) } } #[derive(Clone)] -pub struct StdScheduledMutator +pub struct StdScheduledMutator where -I: Input, -R: Rand, -S: HasRand,{ - mutations: Vec>, + I: Input, +{ + mutations: Vec>, max_size: usize, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where I: Input, - R: Rand, - S: HasRand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -77,31 +74,27 @@ where } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where I: Input, - R: Rand, - S: HasRand, { fn mutate( &mut self, - rand: &mut R, + fuzzer: &F, state: &mut S, input: &mut I, _stage_idx: i32, ) -> Result<(), Error> { - self.scheduled_mutate(state, input, _stage_idx) + self.scheduled_mutate(fuzzer, state, input, _stage_idx) } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where I: Input, - R: Rand, - S: HasRand, { #[inline] - fn mutation_by_idx(&self, index: usize) -> MutationFunction { + fn mutation_by_idx(&self, index: usize) -> MutationFunction { self.mutations[index] } @@ -111,25 +104,21 @@ 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, - R: Rand, - S: HasRand, { // Just use the default methods } -impl HasMaxSize for StdScheduledMutator +impl HasMaxSize for StdScheduledMutator where I: Input, - R: Rand, - S: HasRand, { #[inline] fn max_size(&self) -> usize { @@ -142,11 +131,9 @@ where } } -impl StdScheduledMutator +impl StdScheduledMutator where I: Input, - R: Rand, - S: HasRand, { /// Create a new StdScheduledMutator instance without mutations and corpus pub fn new() -> Self { @@ -157,7 +144,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, @@ -167,21 +154,21 @@ 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, I, R, S)>, + phantom: PhantomData<(C, F, 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, @@ -190,12 +177,12 @@ where /// Mutate bytes fn mutate( &mut self, - rand: &mut R, + fuzzer: &mut F, state: &mut S, input: &mut I, stage_idx: i32, ) -> Result<(), Error> { - self.scheduled.mutate(state, input, stage_idx)?; + self.scheduled.mutate(fuzzer, state, input, stage_idx)?; /*let num = self.scheduled.iterations(state, input); for _ in 0..num { let idx = self.scheduled.schedule(14, state, input); @@ -221,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, @@ -240,9 +227,9 @@ where } } -impl HavocBytesMutator +impl HavocBytesMutator where - SM: ScheduledMutator + HasMaxSize, + SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, C: Corpus, @@ -259,7 +246,7 @@ where } } -impl Default for HavocBytesMutator> +impl Default for HavocBytesMutator> where I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, @@ -268,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); @@ -384,4 +371,4 @@ mod tests { } } } -*/ \ No newline at end of file +*/ diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 940b7d7c71..35db374be4 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -2,90 +2,64 @@ pub mod mutational; pub use mutational::StdMutationalStage; use crate::{ - bolts::tuples::TupleList, - corpus::Corpus, - events::EventManager, - executors::{Executor}, - inputs::Input, - Error, + bolts::tuples::TupleList, corpus::Corpus, 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 -where - I: Input -{ +pub trait Stage { /// Run the stage - fn perform( + fn perform( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor; + ) -> Result<(), Error>; } -pub trait StagesTuple -where - I: Input -{ - fn perform_all( +pub trait StagesTuple { + fn perform_all( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor; + ) -> Result<(), Error>; } -impl StagesTuple for () -where - I: Input -{ - fn perform_all( +impl StagesTuple for () { + fn perform_all( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor - { + ) -> Result<(), Error> { Ok(()) } } -impl StagesTuple for (Head, Tail) +impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple + TupleList, - I: Input + Head: Stage, + Tail: StagesTuple + TupleList, { - fn perform_all( + fn perform_all( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor - { - self.0.perform(fuzzer, state, executor, manager, corpus_idx)?; - self.1 .perform_all(fuzzer, state, executor, manager, corpus_idx) + ) -> Result<(), Error> { + self.0 + .perform(fuzzer, state, executor, manager, corpus_idx)?; + self.1 + .perform_all(fuzzer, state, executor, manager, corpus_idx) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index c45574446d..89e08e8a9d 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -2,14 +2,14 @@ use core::marker::PhantomData; use crate::{ events::EventManager, - executors::{Executor}, + executors::Executor, inputs::Input, mutators::Mutator, stages::Corpus, stages::Stage, - state::{HasRand}, + state::HasRand, + state::{Evaluator, HasCorpus}, utils::Rand, - state::{HasCorpus, Evaluator}, Error, }; @@ -45,7 +45,7 @@ where EM: EventManager, E: Executor, S: HasCorpus + Evaluator, - C: Corpus + C: Corpus, { let num = self.iterations(state); for i in 0..num { @@ -56,11 +56,12 @@ where .load_input()? .clone(); self.mutator_mut() - .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)?; - self.mutator_mut().post_exec(state, fitness, i as i32)?; + self.mutator_mut() + .post_exec(fuzzer, state, fitness, i as i32)?; } Ok(()) } @@ -100,7 +101,7 @@ where fn iterations(&mut self, state: &mut S) -> usize where S: HasRand, - R: Rand + R: Rand, { 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize } @@ -124,7 +125,7 @@ where EM: EventManager, E: Executor, S: HasCorpus + Evaluator, - C: Corpus + C: Corpus, { self.perform_mutational(fuzzer, state, executor, manager, corpus_idx) } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index bcfe3d11e7..0b11d67ade 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -17,7 +17,7 @@ use crate::{ generators::Generator, inputs::Input, observers::ObserversTuple, - utils::{current_milliseconds, Rand}, + utils::Rand, Error, }; @@ -80,7 +80,7 @@ pub trait HasMetadata { pub trait HasFeedbacks where FT: FeedbacksTuple, - I: Input + I: Input, { /// The feedbacks tuple fn feedbacks(&self) -> &FT; @@ -97,7 +97,11 @@ where /// Creates a new testcase, appending the metadata from each feedback #[inline] - fn testcase_with_feedbacks_metadata(&mut self, input: I, fitness: u32) -> Result, Error> { + fn testcase_with_feedbacks_metadata( + &mut self, + input: I, + fitness: u32, + ) -> Result, Error> { let mut testcase = Testcase::with_fitness(input, fitness); self.feedbacks_mut().append_metadata_all(&mut testcase)?; Ok(testcase) @@ -108,7 +112,7 @@ where pub trait HasObjectives where FT: FeedbacksTuple, - I: Input + I: Input, { /// The objective feedbacks tuple fn objectives(&self) -> &FT; @@ -118,8 +122,7 @@ where } /// Trait for the execution counter -pub trait HasExecutions -{ +pub trait HasExecutions { /// The executions counter fn executions(&self) -> &usize; @@ -128,8 +131,7 @@ pub trait HasExecutions } /// Trait for the starting time -pub trait HasStartTime -{ +pub trait HasStartTime { /// The starting time fn start_time(&self) -> &Duration; @@ -140,7 +142,7 @@ pub trait HasStartTime /// Add to the state if interesting pub trait IfInteresting where - I: Input + I: Input, { /// Evaluate if a set of observation channels has an interesting state fn is_interesting( @@ -205,7 +207,6 @@ where phantom: PhantomData, } - impl HasRand for State where C: Corpus, @@ -228,7 +229,6 @@ where } } - impl HasCorpus for State where C: Corpus, @@ -471,7 +471,6 @@ where } } - #[cfg(feature = "std")] impl State where @@ -551,7 +550,6 @@ where } } - impl State where C: Corpus, @@ -584,13 +582,14 @@ where executor.post_exec_observers()?; let observers = executor.observers(); - let fitness = self .feedbacks_mut() .is_interesting_all(&input, observers, exit_kind)?; - - let is_solution = self.objectives_mut().is_interesting_all(&input, observers, exit_kind.clone())? > 0; + let is_solution = + self.objectives_mut() + .is_interesting_all(&input, observers, exit_kind.clone())? + > 0; Ok((fitness, is_solution)) } @@ -629,7 +628,7 @@ where Ok(()) } - pub fn new(rand: R, corpus: C, feedbacks: FT, solutions: SC, objectives: OFT) -> Self { + pub fn new(rand: R, corpus: C, feedbacks: FT, solutions: SC, objectives: OFT) -> Self { Self { rand, executions: 0, From c411fec2718309ee08039977062eb848a6698c39 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 22 Feb 2021 11:26:11 +0100 Subject: [PATCH 07/10] scozz --- libafl/benches/rand_speeds.rs | 2 +- libafl/build.rs | 16 ++-- libafl/src/bolts/mod.rs | 2 +- libafl/src/bolts/serdeany.rs | 2 +- libafl/src/bolts/shmem.rs | 3 +- libafl/src/bolts/tuples.rs | 16 ++-- libafl/src/corpus/mod.rs | 72 ++++++---------- libafl/src/events/llmp.rs | 68 +++++++-------- libafl/src/events/logger.rs | 16 ++-- libafl/src/events/mod.rs | 23 ++++-- libafl/src/executors/inprocess.rs | 12 +-- libafl/src/executors/mod.rs | 11 +-- libafl/src/fuzzer.rs | 110 ++++++++----------------- libafl/src/inputs/bytes.rs | 2 +- libafl/src/inputs/mod.rs | 1 - libafl/src/lib.rs | 4 +- libafl/src/mutators/mod.rs | 20 ++--- libafl/src/mutators/mutations.rs | 78 ++++++++++-------- libafl/src/mutators/scheduled.rs | 74 ++++++++++------- libafl/src/mutators/token_mutations.rs | 2 +- libafl/src/stages/mod.rs | 5 +- libafl/src/stages/mutational.rs | 89 +++++++++++--------- libafl/src/state/mod.rs | 19 +++-- libafl/src/utils.rs | 2 +- 24 files changed, 314 insertions(+), 335 deletions(-) diff --git a/libafl/benches/rand_speeds.rs b/libafl/benches/rand_speeds.rs index ad97bd747b..486343d0cc 100644 --- a/libafl/benches/rand_speeds.rs +++ b/libafl/benches/rand_speeds.rs @@ -1,9 +1,9 @@ //! Compare the speed of rand implementations +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use libafl::utils::{ Lehmer64Rand, Rand, RomuDuoJrRand, RomuTrioRand, XorShift64Rand, Xoshiro256StarRand, }; -use criterion::{black_box, criterion_group, criterion_main, Criterion}; fn criterion_benchmark(c: &mut Criterion) { let mut xorshift = XorShift64Rand::new(1); diff --git a/libafl/build.rs b/libafl/build.rs index f77872e9a6..1c6e87c8ce 100644 --- a/libafl/build.rs +++ b/libafl/build.rs @@ -1,11 +1,9 @@ fn main() { - - #[cfg(target_os = "windows")] - windows::build!( - windows::win32::system_services::HANDLE, - windows::win32::windows_programming::CloseHandle, - // API needed for the shared memory - windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile}, - ); - + #[cfg(target_os = "windows")] + windows::build!( + windows::win32::system_services::HANDLE, + windows::win32::windows_programming::CloseHandle, + // API needed for the shared memory + windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile}, + ); } diff --git a/libafl/src/bolts/mod.rs b/libafl/src/bolts/mod.rs index 099a20e799..f73268ce7c 100644 --- a/libafl/src/bolts/mod.rs +++ b/libafl/src/bolts/mod.rs @@ -1,8 +1,8 @@ //! Bolts are no conceptual fuzzing elements, but they keep libafl-based fuzzers together. +pub mod bindings; pub mod llmp; pub mod ownedref; pub mod serdeany; pub mod shmem; pub mod tuples; -pub mod bindings; diff --git a/libafl/src/bolts/serdeany.rs b/libafl/src/bolts/serdeany.rs index d7cf5dc7e9..8fcd3ae208 100644 --- a/libafl/src/bolts/serdeany.rs +++ b/libafl/src/bolts/serdeany.rs @@ -512,7 +512,7 @@ macro_rules! impl_serdeany { self } } - + #[allow(non_snake_case)] #[cfg(feature = "std")] #[ctor] diff --git a/libafl/src/bolts/shmem.rs b/libafl/src/bolts/shmem.rs index 324f6d512a..cc4d4f962f 100644 --- a/libafl/src/bolts/shmem.rs +++ b/libafl/src/bolts/shmem.rs @@ -330,8 +330,8 @@ pub mod shmem { use core::{mem::size_of, slice}; use std::ffi::CStr; - use crate::Error; use super::ShMem; + use crate::Error; /// The default Sharedmap impl for windows using shmctl & shmget #[derive(Clone, Debug)] @@ -343,7 +343,6 @@ pub mod shmem { } // TODO complete - } #[cfg(test)] diff --git a/libafl/src/bolts/tuples.rs b/libafl/src/bolts/tuples.rs index 2cd2d51d9e..ba20a0f29a 100644 --- a/libafl/src/bolts/tuples.rs +++ b/libafl/src/bolts/tuples.rs @@ -190,9 +190,9 @@ macro_rules! tuple_for_each { } impl ForEach for () { - fn for_each(&self) { } + fn for_each(&self) {} } - + impl ForEach for (Head, Tail) where Head: $trait_name, @@ -206,7 +206,7 @@ macro_rules! tuple_for_each { } { use $fn_name::*; - + $tuple_name.for_each(); }; }; @@ -221,9 +221,9 @@ macro_rules! tuple_for_each_mut { } impl ForEachMut for () { - fn for_each_mut(&mut self) { } + fn for_each_mut(&mut self) {} } - + impl ForEachMut for (Head, Tail) where Head: $trait_name, @@ -237,7 +237,7 @@ macro_rules! tuple_for_each_mut { } { use $fn_name::*; - + $tuple_name.for_each_mut(); }; }; @@ -245,13 +245,13 @@ macro_rules! tuple_for_each_mut { /* pub fn test_macros() { - + let mut t = tuple_list!(1, "a"); tuple_for_each!(f1, std::fmt::Display, t, |x| { println!("{}", x); }); - + tuple_for_each_mut!(f2, std::fmt::Display, t, |x| { println!("{}", x); }); diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 02493aa84b..32069c5f46 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -7,12 +7,7 @@ use alloc::vec::Vec; use core::cell::RefCell; use serde::{Deserialize, Serialize}; -use crate::{ - inputs::Input, - state::{HasCorpus, HasRand}, - utils::Rand, - Error, -}; +use crate::{inputs::Input, Error}; /// Corpus with all current testcases pub trait Corpus: serde::Serialize + serde::de::DeserializeOwned @@ -33,65 +28,41 @@ where /// Get by id fn get(&self, idx: usize) -> Result<&RefCell>, Error>; + + /// Current testcase scheduled + fn current(&self) -> &Option; + + /// Current testcase scheduled (mut) + fn current_mut(&mut self) -> &mut Option; } -pub trait CorpusScheduler { +pub trait CorpusScheduler +where + I: Input, +{ /// Add an entry to the corpus and return its index - fn on_add( - &self, - state: &mut S, - idx: usize, - testcase: &Testcase, - ) -> Result<(), Error> - where - S: HasCorpus + HasRand, - C: Corpus, - I: Input, - R: Rand, - { + fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { Ok(()) } /// Replaces the testcase at the given idx - fn on_replace( - &self, - state: &mut S, - idx: usize, - testcase: &Testcase, - ) -> Result<(), Error> - where - S: HasCorpus + HasRand, - C: Corpus, - I: Input, - R: Rand, - { + fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { Ok(()) } /// Removes an entry from the corpus, returning it if it was present. - fn on_remove( + fn on_remove( &self, state: &mut S, idx: usize, testcase: &Option>, - ) -> Result<(), Error> - where - S: HasCorpus + HasRand, - C: Corpus, - I: Input, - R: Rand, - { + ) -> Result<(), Error> { Ok(()) } // TODO: IntoIter /// Gets the next entry - fn next(&self, state: &mut S) -> Result - where - S: HasCorpus + HasRand, - C: Corpus, - I: Input, - R: Rand; + fn next(&self, state: &mut S) -> Result; } /* @@ -124,6 +95,7 @@ where I: Input, { entries: Vec>>, + current: Option, } impl Corpus for InMemoryCorpus @@ -168,4 +140,14 @@ where fn get(&self, idx: usize) -> Result<&RefCell>, Error> { Ok(&self.entries[idx]) } + + /// Current testcase scheduled + fn current(&self) -> &Option { + &self.current + } + + /// Current testcase scheduled (mut) + fn current_mut(&mut self) -> &mut Option { + &mut self.current + } } diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 27f6078ab3..2d7e82aaa8 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -39,23 +39,25 @@ const _LLMP_TAG_RESTART: llmp::Tag = 0x8357A87; const _LLMP_TAG_NO_RESTART: llmp::Tag = 0x57A7EE71; #[derive(Clone, Debug)] -pub struct LlmpEventManager +pub struct LlmpEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, //CE: CustomEvent, { stats: Option, llmp: llmp::LlmpConnection, - phantom: PhantomData, + phantom: PhantomData<(I, S)>, } #[cfg(feature = "std")] #[cfg(unix)] -impl LlmpEventManager +impl LlmpEventManager where I: Input, + S: IfInteresting, ST: Stats, { /// Create llmp on a port @@ -78,9 +80,10 @@ where } } -impl Drop for LlmpEventManager +impl Drop for LlmpEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, { @@ -90,9 +93,10 @@ where } } -impl LlmpEventManager +impl LlmpEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, { @@ -248,7 +252,7 @@ where } // Handle arriving events in the client - fn handle_in_client( + fn handle_in_client( &mut self, state: &mut S, sender_id: u32, @@ -258,7 +262,6 @@ where where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting, { match event { Event::NewTestcase { @@ -293,9 +296,10 @@ where } } -impl EventManager for LlmpEventManager +impl EventManager for LlmpEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, //CE: CustomEvent, { @@ -311,11 +315,10 @@ where } } - fn process(&mut self, state: &mut S, executor: &mut E) -> Result + fn process(&mut self, state: &mut S, executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting, { // TODO: Get around local event copy by moving handle_in_client let mut events = vec![]; @@ -344,7 +347,7 @@ where Ok(count) } - fn fire(&mut self, _state: &mut S, event: Event) -> Result<(), Error> { + fn fire(&mut self, _state: &mut S, event: Event) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; Ok(()) @@ -356,11 +359,11 @@ where /// This method is needed when the fuzzer run crashes and has to restart. pub fn serialize_state_mgr( state: &S, - mgr: &LlmpEventManager, + mgr: &LlmpEventManager, ) -> Result, Error> where I: Input, - S: Serialize, + S: Serialize + IfInteresting, SH: ShMem, ST: Stats, { @@ -370,10 +373,10 @@ where /// Deserialize the state and corpus tuple, previously serialized with `serialize_state_corpus(...)` pub fn deserialize_state_mgr( state_corpus_serialized: &[u8], -) -> Result<(S, LlmpEventManager), Error> +) -> Result<(S, LlmpEventManager), Error> where I: Input, - S: DeserializeOwned, + S: DeserializeOwned + IfInteresting, SH: ShMem, ST: Stats, { @@ -386,22 +389,24 @@ where /// A manager that can restart on the fly, storing states in-between (in `on_resatrt`) #[derive(Clone, Debug)] -pub struct LlmpRestartingEventManager +pub struct LlmpRestartingEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, //CE: CustomEvent, { /// The embedded llmp event manager - llmp_mgr: LlmpEventManager, + llmp_mgr: LlmpEventManager, /// The sender to serialize the state for the next runner sender: LlmpSender, } -impl EventManager for LlmpRestartingEventManager +impl EventManager for LlmpRestartingEventManager where I: Input, + S: IfInteresting + Serialize, SH: ShMem, ST: Stats, //CE: CustomEvent, { @@ -413,10 +418,7 @@ where } /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. - fn on_restart(&mut self, state: &mut S) -> Result<(), Error> - where - S: Serialize, - { + fn on_restart(&mut self, state: &mut S) -> Result<(), Error> { // First, reset the page to 0 so the next iteration can read read from the beginning of this page unsafe { self.sender.reset() }; let state_corpus_serialized = serialize_state_mgr(state, &self.llmp_mgr)?; @@ -424,16 +426,15 @@ where .send_buf(_LLMP_TAG_RESTART, &state_corpus_serialized) } - fn process(&mut self, state: &mut S, executor: &mut E) -> Result + fn process(&mut self, state: &mut S, executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, - S: IfInteresting, { self.llmp_mgr.process(state, executor) } - fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error> { + fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error> { // Check if we are going to crash in the event, in which case we store our current state for the next runner self.llmp_mgr.fire(state, event) } @@ -445,14 +446,15 @@ const _ENV_FUZZER_RECEIVER: &str = &"_AFL_ENV_FUZZER_RECEIVER"; /// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages) const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT"; -impl LlmpRestartingEventManager +impl LlmpRestartingEventManager where I: Input, + S: IfInteresting, SH: ShMem, ST: Stats, //CE: CustomEvent, { /// Create a new runner, the executed child doing the actual fuzzing. - pub fn new(llmp_mgr: LlmpEventManager, sender: LlmpSender) -> Self { + pub fn new(llmp_mgr: LlmpEventManager, sender: LlmpSender) -> Self { Self { llmp_mgr, sender } } @@ -471,13 +473,13 @@ where /// The restarter will start a new process each time the child crashes or timeouts. #[cfg(feature = "std")] pub fn setup_restarting_mgr( - //mgr: &mut LlmpEventManager, + //mgr: &mut LlmpEventManager, stats: ST, broker_port: u16, -) -> Result<(Option, LlmpRestartingEventManager), Error> +) -> Result<(Option, LlmpRestartingEventManager), Error> where I: Input, - S: DeserializeOwned, + S: DeserializeOwned + IfInteresting, SH: ShMem, ST: Stats, { @@ -485,7 +487,7 @@ where // We start ourself as child process to actually fuzz if std::env::var(_ENV_FUZZER_SENDER).is_err() { - mgr = LlmpEventManager::::new_on_port(stats, broker_port)?; + mgr = LlmpEventManager::::new_on_port(stats, broker_port)?; if mgr.is_broker() { // Yep, broker. Just loop here. println!("Doing broker things. Run this tool again to start fuzzing in a client."); @@ -528,7 +530,7 @@ where None => { println!("First run. Let's set it all up"); // Mgr to send and receive msgs from/to all other fuzzer instances - let client_mgr = LlmpEventManager::::existing_client_from_env( + let client_mgr = LlmpEventManager::::existing_client_from_env( _ENV_FUZZER_BROKER_CLIENT_INITIAL, )?; @@ -537,7 +539,7 @@ where // Restoring from a previous run, deserialize state and corpus. Some((_sender, _tag, msg)) => { println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); - let (state, mgr): (S, LlmpEventManager) = deserialize_state_mgr(&msg)?; + let (state, mgr): (S, LlmpEventManager) = deserialize_state_mgr(&msg)?; (Some(state), LlmpRestartingEventManager::new(mgr, sender)) } diff --git a/libafl/src/events/logger.rs b/libafl/src/events/logger.rs index 0a37f9b8f2..4262d847a3 100644 --- a/libafl/src/events/logger.rs +++ b/libafl/src/events/logger.rs @@ -5,14 +5,16 @@ use core::marker::PhantomData; #[cfg(unix)] use crate::{ events::{BrokerEventResult, Event, EventManager}, + executors::{Executor, HasObservers}, inputs::Input, + observers::ObserversTuple, stats::Stats, Error, }; /// A simple, single-threaded event manager that just logs #[derive(Clone, Debug)] -pub struct LoggerEventManager +pub struct LoggerEventManager where I: Input, ST: Stats, //CE: CustomEvent, @@ -21,15 +23,19 @@ where stats: ST, /// The events that happened since the last handle_in_broker events: Vec>, - phantom: PhantomData<(E, S)>, + phantom: PhantomData, } -impl EventManager for LoggerEventManager +impl EventManager for LoggerEventManager where I: Input, ST: Stats, //CE: CustomEvent, { - fn process(&mut self, state: &mut S, _executor: &mut E) -> Result { + fn process(&mut self, state: &mut S, executor: &mut E) -> Result + where + E: Executor + HasObservers, + OT: ObserversTuple, + { let count = self.events.len(); while self.events.len() > 0 { let event = self.events.pop().unwrap(); @@ -47,7 +53,7 @@ where } } -impl LoggerEventManager +impl LoggerEventManager where I: Input, ST: Stats, //TODO CE: CustomEvent, diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index a1c03ff11f..40e0fe05c6 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -9,7 +9,10 @@ use core::{fmt, marker::PhantomData, time::Duration}; use serde::{Deserialize, Serialize}; use crate::{ - executors::Executor, inputs::Input, observers::ObserversTuple, state::IfInteresting, Error, + executors::{Executor, HasObservers}, + inputs::Input, + observers::ObserversTuple, + Error, }; /// The log event severity @@ -146,7 +149,7 @@ where /// EventManager is the main communications hub. /// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager` -pub trait EventManager +pub trait EventManager where I: Input, { @@ -155,7 +158,10 @@ where /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process(&mut self, state: &mut S, executor: &mut E) -> Result; + fn process(&mut self, state: &mut S, executor: &mut E) -> Result + where + E: Executor + HasObservers, + OT: ObserversTuple; /// Serialize all observers for this type and manager fn serialize_observers(&mut self, observers: &OT) -> Result, Error> @@ -189,16 +195,17 @@ where /// An eventmgr for tests, and as placeholder if you really don't need an event manager. #[derive(Copy, Clone, Debug)] -pub struct NopEventManager { - phantom: PhantomData<(E, I, S)>, +pub struct NopEventManager { + phantom: PhantomData<(I, S)>, } -impl EventManager for NopEventManager +impl EventManager for NopEventManager where I: Input, { - fn process(&mut self, _state: &mut S, _executor: &mut E) -> Result + fn process(&mut self, state: &mut S, executor: &mut E) -> Result where - E: Executor, + E: Executor + HasObservers, + OT: ObserversTuple, { Ok(0) } diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 76a1d72a9b..36972050c5 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -56,7 +56,7 @@ where #[inline] fn pre_exec(&mut self, state: &mut S, event_mgr: &mut EM, input: &I) -> Result<(), Error> where - EM: EventManager, + EM: EventManager, { #[cfg(unix)] #[cfg(feature = "std")] @@ -69,7 +69,7 @@ where #[inline] fn post_exec(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> where - EM: EventManager, + EM: EventManager, { #[cfg(unix)] #[cfg(feature = "std")] @@ -132,7 +132,7 @@ where _event_mgr: &mut EM, ) -> Self where - EM: EventManager, + EM: EventManager, OC: Corpus, OFT: FeedbacksTuple, S: HasObjectives + HasSolutions, @@ -200,7 +200,7 @@ pub mod unix_signals { info: siginfo_t, _void: c_void, ) where - EM: EventManager, + EM: EventManager, OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, @@ -273,7 +273,7 @@ pub mod unix_signals { info: siginfo_t, _void: c_void, ) where - EM: EventManager, + EM: EventManager, OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, @@ -346,7 +346,7 @@ pub mod unix_signals { pub unsafe fn setup_crash_handlers() where - EM: EventManager, + EM: EventManager, OT: ObserversTuple, OC: Corpus, OFT: FeedbacksTuple, diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 7a4a794e0d..dfe2740203 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -87,21 +87,16 @@ where _input: &I, ) -> Result<(), Error> where - EM: EventManager, + EM: EventManager, { Ok(()) } #[inline] /// Called right after execution finished. - fn post_exec( - &mut self, - _state: &S, - _event_mgr: &mut EM, - _input: &I, - ) -> Result<(), Error> + fn post_exec(&mut self, _state: &S, _event_mgr: &mut EM, _input: &I) -> Result<(), Error> where - EM: EventManager, + EM: EventManager, { Ok(()) } diff --git a/libafl/src/fuzzer.rs b/libafl/src/fuzzer.rs index 88f5960c94..37c986a26c 100644 --- a/libafl/src/fuzzer.rs +++ b/libafl/src/fuzzer.rs @@ -1,20 +1,20 @@ use crate::{ - corpus::{Corpus, CorpusScheduler}, + corpus::CorpusScheduler, events::{Event, EventManager}, - executors::Executor, + executors::{Executor, HasObservers}, inputs::Input, + observers::ObserversTuple, stages::StagesTuple, - state::{HasCorpus, HasExecutions, HasRand}, - utils::{current_milliseconds, current_time, Rand}, + state::HasExecutions, + utils::{current_milliseconds, current_time}, Error, }; use core::marker::PhantomData; /// Holds a set of stages -pub trait HasStages +pub trait HasStages: Sized where - ST: StagesTuple, - I: Input, + ST: StagesTuple, { fn stages(&self) -> &ST; @@ -22,9 +22,10 @@ where } /// Holds a scheduler -pub trait HasCorpusScheduler +pub trait HasCorpusScheduler where - CS: CorpusScheduler, + CS: CorpusScheduler, + I: Input, { fn scheduler(&self) -> &CS; @@ -32,50 +33,29 @@ where } /// The main fuzzer trait. -pub trait Fuzzer: HasCorpusScheduler + HasStages -where - CS: CorpusScheduler, - ST: StagesTuple, - I: Input, -{ - fn fuzz_one( - &self, - state: &mut S, - executor: &mut E, - manager: &mut EM, - ) -> Result - where - EM: EventManager, - E: Executor; +pub trait Fuzzer { + fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result; - fn fuzz_loop( - &self, - state: &mut S, - executor: &mut E, - manager: &mut EM, - ) -> Result - where - EM: EventManager, - E: Executor; + fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result; } /// Your default fuzzer instance, for everyday use. #[derive(Clone, Debug)] -pub struct StdFuzzer +pub struct StdFuzzer where - CS: CorpusScheduler, - ST: StagesTuple, + CS: CorpusScheduler, + ST: StagesTuple, I: Input, { scheduler: CS, stages: ST, - phantom: PhantomData, + phantom: PhantomData<(E, EM, I, OT, S)>, } -impl HasStages for StdFuzzer +impl HasStages for StdFuzzer where - CS: CorpusScheduler, - ST: StagesTuple, + CS: CorpusScheduler, + ST: StagesTuple, I: Input, { fn stages(&self) -> &ST { @@ -87,10 +67,10 @@ where } } -impl HasCorpusScheduler for StdFuzzer +impl HasCorpusScheduler for StdFuzzer where - CS: CorpusScheduler, - ST: StagesTuple, + CS: CorpusScheduler, + ST: StagesTuple, I: Input, { fn scheduler(&self) -> &CS { @@ -102,25 +82,17 @@ where } } -impl Fuzzer for StdFuzzer +impl Fuzzer for StdFuzzer where - CS: CorpusScheduler, - ST: StagesTuple, + CS: CorpusScheduler, + S: HasExecutions, + ST: StagesTuple, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, I: Input, { - fn fuzz_one( - &self, - state: &mut S, - executor: &mut E, - manager: &mut EM, - ) -> Result - where - EM: EventManager, - E: Executor, - S: HasCorpus + HasRand, - C: Corpus, - R: Rand, - { + fn fuzz_one(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result { let idx = self.scheduler().next(state)?; self.stages() @@ -130,19 +102,7 @@ where Ok(idx) } - fn fuzz_loop( - &self, - state: &mut S, - executor: &mut E, - manager: &mut EM, - ) -> Result - where - EM: EventManager, - E: Executor, - S: HasCorpus + HasRand + HasExecutions, - C: Corpus, - R: Rand, - { + fn fuzz_loop(&self, state: &mut S, executor: &mut E, manager: &mut EM) -> Result { let mut last = current_milliseconds(); loop { self.fuzz_one(state, executor, manager)?; @@ -162,10 +122,10 @@ where } } -impl StdFuzzer +impl StdFuzzer where - CS: CorpusScheduler, - ST: StagesTuple, + CS: CorpusScheduler, + ST: StagesTuple, I: Input, { pub fn new(scheduler: CS, stages: ST) -> Self { diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index b622a002f7..1cca7ee368 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -5,7 +5,7 @@ use alloc::{borrow::ToOwned, rc::Rc, vec::Vec}; use core::{cell::RefCell, convert::From}; use serde::{Deserialize, Serialize}; -use crate::inputs::{HasBytesVec, HasTargetBytes, HasLen, Input, TargetBytes}; +use crate::inputs::{HasBytesVec, HasLen, HasTargetBytes, Input, TargetBytes}; /// A bytes input is the basic input #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq)] diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 09a62f698a..18b9b6a518 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -106,4 +106,3 @@ pub trait HasLen { /// The lenght fn len(&self) -> usize; } - diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 0101e09da1..c8f30e87d3 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -29,7 +29,7 @@ pub mod fuzzer; pub use fuzzer::*; use alloc::string::String; -use core::{fmt}; +use core::fmt; #[cfg(feature = "std")] use std::{env::VarError, io, num::ParseIntError, string::FromUtf8Error}; @@ -199,4 +199,4 @@ mod tests { assert_eq!(state.corpus().count(), corpus_deserialized.count()); } } -*/ \ No newline at end of file +*/ diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 3bbd89d98b..73c5203663 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -7,32 +7,24 @@ pub use mutations::*; pub mod token_mutations; pub use token_mutations::*; -use crate::{ - inputs::Input, - Error, -}; +use crate::{inputs::Input, Error}; // TODO mutator stats method that produces something that can be sent with the NewTestcase event // We can use it to report which mutations generated the testcase in the broker logs /// 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( - &mut self, - fuzzer: &F, - state: &mut S, - input: &mut I, - stage_idx: i32, - ) -> Result<(), Error>; + fn mutate(&self, fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32) + -> Result<(), Error>; /// Post-process given the outcome of the execution - fn post_exec( - &mut self, + fn post_exec( + &self, _fuzzer: &F, _state: &mut S, _is_interesting: u32, diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 2813a1ebc8..c2af06a1c2 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -27,8 +27,7 @@ pub enum MutationResult { // TODO maybe the mutator arg is not needed /// The generic function type that identifies mutations -pub type MutationFunction = - fn(&mut M, &F, &mut S, &mut I) -> Result; +pub type MutationFunction = fn(&M, &F, &mut S, &mut I) -> Result; pub trait ComposedByMutations where @@ -125,7 +124,7 @@ const INTERESTING_32: [i32; 27] = [ /// Bitflip mutation for inputs with a bytes vector pub fn mutation_bitflip( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -148,7 +147,7 @@ where } pub fn mutation_byteflip( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -171,7 +170,7 @@ where } pub fn mutation_byteinc( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -195,7 +194,7 @@ where } pub fn mutation_bytedec( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -219,7 +218,7 @@ where } pub fn mutation_byteneg( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -242,7 +241,7 @@ where } pub fn mutation_byterand( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -265,7 +264,7 @@ where } pub fn mutation_byteadd( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -293,7 +292,7 @@ where } pub fn mutation_wordadd( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -323,7 +322,7 @@ where } pub fn mutation_dwordadd( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -353,7 +352,7 @@ where } pub fn mutation_qwordadd( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -383,7 +382,7 @@ where } pub fn mutation_byteinteresting( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -407,7 +406,7 @@ where } pub fn mutation_wordinteresting( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -437,7 +436,7 @@ where } pub fn mutation_dwordinteresting( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -467,7 +466,7 @@ where } pub fn mutation_bytesdelete( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -490,7 +489,7 @@ where } pub fn mutation_bytesexpand( - mutator: &mut M, + mutator: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -520,7 +519,7 @@ where } pub fn mutation_bytesinsert( - mutator: &mut M, + mutator: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -553,7 +552,7 @@ where } pub fn mutation_bytesrandinsert( - mutator: &mut M, + mutator: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -586,7 +585,7 @@ where } pub fn mutation_bytesset( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -611,7 +610,7 @@ where } pub fn mutation_bytesrandset( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -636,7 +635,7 @@ where } pub fn mutation_bytescopy( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -661,7 +660,7 @@ where } pub fn mutation_bytesswap( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -689,7 +688,7 @@ where /// Crossover insert mutation pub fn mutation_crossover_insert( - mutator: &mut M, + mutator: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -704,10 +703,13 @@ where let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.random_corpus_entry()?; - if idx == state.corpus().current_testcase().1 { - return Ok(MutationResult::Skipped); + let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + if let Some(cur) = state.corpus().current() { + if idx == *cur { + return Ok(MutationResult::Skipped); + } } + let other_testcase = state.corpus().get(idx)?; let mut other_ref = other_testcase.borrow_mut(); let other = other_ref.load_input()?; @@ -738,7 +740,7 @@ where /// Crossover replace mutation pub fn mutation_crossover_replace( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -752,10 +754,13 @@ where let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.random_corpus_entry()?; - if idx == state.corpus().current_testcase().1 { - return Ok(MutationResult::Skipped); + let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + if let Some(cur) = state.corpus().current() { + if idx == *cur { + return Ok(MutationResult::Skipped); + } } + let other_testcase = state.corpus().get(idx)?; let mut other_ref = other_testcase.borrow_mut(); let other = other_ref.load_input()?; @@ -792,7 +797,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { /// Splicing mutation from AFL pub fn mutation_splice( - _: &mut M, + _: &M, fuzzer: &F, state: &mut S, input: &mut I, @@ -804,10 +809,13 @@ where S: HasRand + HasCorpus, { // We don't want to use the testcase we're already using for splicing - let (other_testcase, idx) = state.random_corpus_entry()?; - if idx == state.corpus().current_testcase().1 { - return Ok(MutationResult::Skipped); + let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + if let Some(cur) = state.corpus().current() { + if idx == *cur { + return Ok(MutationResult::Skipped); + } } + let other_testcase = state.corpus().get(idx)?; let mut other_ref = other_testcase.borrow_mut(); let other = other_ref.load_input()?; diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index a40e84329e..e8b880e3d9 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -15,27 +15,20 @@ 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, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&mut self, state: &mut S, input: &I) -> u64; - //{ - // 1 << (1 + state.rand_mut().below(6)) - //} + fn iterations(&self, state: &mut S, input: &I) -> u64; /// Get the next mutation to apply - fn schedule(&mut self, mutations_count: usize, state: &mut S, input: &I) -> usize; - //{ - // debug_assert!(mutations_count > 0); - // rand.below(mutations_count as u64) as usize - //} + fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize; /// New default implementation for mutate /// Implementations must forward mutate() to this method fn scheduled_mutate( - &mut self, + &self, fuzzer: &F, state: &mut S, input: &mut I, @@ -50,18 +43,22 @@ where } } -#[derive(Clone)] -pub struct StdScheduledMutator +pub struct StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { mutations: Vec>, max_size: usize, + phantom: PhantomData, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -74,12 +71,14 @@ where } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { fn mutate( - &mut self, + &self, fuzzer: &F, state: &mut S, input: &mut I, @@ -89,9 +88,11 @@ where } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { #[inline] fn mutation_by_idx(&self, index: usize) -> MutationFunction { @@ -109,16 +110,29 @@ where } } -impl ScheduledMutator for StdScheduledMutator +impl ScheduledMutator for StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { - // Just use the default methods + /// Compute the number of iterations used to apply stacked mutations + fn iterations(&self, state: &mut S, input: &I) -> u64 { + 1 << (1 + state.rand_mut().below(6)) + } + + /// Get the next mutation to apply + fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize { + debug_assert!(mutations_count > 0); + state.rand_mut().below(mutations_count as u64) as usize + } } -impl HasMaxSize for StdScheduledMutator +impl HasMaxSize for StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { #[inline] fn max_size(&self) -> usize { @@ -131,15 +145,18 @@ where } } -impl StdScheduledMutator +impl StdScheduledMutator where I: Input, + S: HasRand, + R: Rand, { /// Create a new StdScheduledMutator instance without mutations and corpus pub fn new() -> Self { Self { mutations: vec![], max_size: DEFAULT_MAX_SIZE, + phantom: PhantomData, } } @@ -148,6 +165,7 @@ where StdScheduledMutator { mutations: mutations, max_size: DEFAULT_MAX_SIZE, + phantom: PhantomData, } } } @@ -166,7 +184,7 @@ where phantom: PhantomData<(C, F, I, R, S)>, } -impl Mutator for HavocBytesMutator +impl Mutator for HavocBytesMutator where SM: ScheduledMutator + HasMaxSize, I: Input + HasBytesVec, @@ -176,8 +194,8 @@ where { /// Mutate bytes fn mutate( - &mut self, - fuzzer: &mut F, + &self, + fuzzer: &F, state: &mut S, input: &mut I, stage_idx: i32, @@ -246,7 +264,7 @@ where } } -impl Default for HavocBytesMutator> +impl Default for HavocBytesMutator> where I: Input + HasBytesVec, S: HasRand + HasCorpus + HasMetadata, @@ -255,7 +273,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); @@ -283,8 +301,8 @@ where scheduled.add_mutation(mutation_bytescopy); scheduled.add_mutation(mutation_bytesswap); - scheduled.add_mutation(mutation_tokeninsert); - scheduled.add_mutation(mutation_tokenreplace); + //scheduled.add_mutation(mutation_tokeninsert); + //scheduled.add_mutation(mutation_tokenreplace); scheduled.add_mutation(mutation_crossover_insert); scheduled.add_mutation(mutation_crossover_replace); diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 71635a33bd..b86937b45f 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -3,8 +3,8 @@ use crate::{ inputs::{HasBytesVec, Input}, - state::{HasRand, HasMetadata}, mutators::*, + state::{HasMetadata, HasRand}, utils::Rand, Error, }; diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 35db374be4..45c4db9b8d 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -1,10 +1,7 @@ pub mod mutational; pub use mutational::StdMutationalStage; -use crate::{ - bolts::tuples::TupleList, corpus::Corpus, events::EventManager, executors::Executor, - inputs::Input, Error, -}; +use crate::{bolts::tuples::TupleList, corpus::Corpus, Error}; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 89e08e8a9d..add170ba89 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -1,14 +1,14 @@ use core::marker::PhantomData; use crate::{ + corpus::Corpus, events::EventManager, - executors::Executor, + executors::{Executor, HasObservers}, inputs::Input, mutators::Mutator, - stages::Corpus, + observers::ObserversTuple, stages::Stage, - state::HasRand, - state::{Evaluator, HasCorpus}, + state::{Evaluator, HasCorpus, HasRand}, utils::Rand, Error, }; @@ -18,10 +18,15 @@ 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, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, { /// The mutator registered for this stage fn mutator(&self) -> &M; @@ -30,23 +35,17 @@ where fn mutator_mut(&mut self) -> &mut M; /// Gets the number of iterations this mutator should run for. - fn iterations(&mut self, state: &mut S) -> usize; + fn iterations(&mut self, state: &mut S) -> usize; /// Runs this (mutational) stage for the given testcase - fn perform_mutational( + fn perform_mutational( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor, - S: HasCorpus + Evaluator, - C: Corpus, - { + ) -> Result<(), Error> { let num = self.iterations(state); for i in 0..num { let mut input_mut = state @@ -71,19 +70,32 @@ 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, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + R: Rand, { mutator: M, - phantom: PhantomData, + phantom: PhantomData<(C, E, EM, F, 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, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + R: Rand, { /// The mutator, added to this stage #[inline] @@ -98,43 +110,46 @@ where } /// Gets the number of iterations as a random number - fn iterations(&mut self, state: &mut S) -> usize - where - S: HasRand, - R: Rand, - { + fn iterations(&mut self, state: &mut S) -> usize { 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize } } -impl Stage for StdMutationalStage +impl Stage + for StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, + S: HasCorpus + Evaluator + HasRand, + C: Corpus, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + R: Rand, { #[inline] - fn perform( + fn perform( &self, fuzzer: &F, state: &mut S, executor: &mut E, manager: &mut EM, corpus_idx: usize, - ) -> Result<(), Error> - where - EM: EventManager, - E: Executor, - S: HasCorpus + Evaluator, - C: Corpus, - { + ) -> Result<(), Error> { self.perform_mutational(fuzzer, state, executor, manager, corpus_idx) } } -impl StdMutationalStage +impl StdMutationalStage where - M: Mutator, + M: Mutator, I: Input, + S: HasCorpus + Evaluator + HasRand, + C: Corpus, + EM: EventManager, + E: Executor + HasObservers, + OT: ObserversTuple, + R: Rand, { /// Creates a new default mutational stage pub fn new(mutator: M) -> Self { diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 0b11d67ade..eddab4e503 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -159,20 +159,21 @@ where } /// Evaluate an input modyfing the state of the fuzzer and returning a fitness -pub trait Evaluator +pub trait Evaluator: Sized where I: Input, { /// Runs the input and triggers observers and feedback - fn evaluate_input( + fn evaluate_input( &mut self, input: I, executor: &mut E, event_mgr: &mut EM, ) -> Result where - E: Executor, - EM: EventManager; + E: Executor + HasObservers, + OT: ObserversTuple, + EM: EventManager; } /// The state a fuzz run. @@ -442,7 +443,7 @@ where E: Executor + HasObservers, OT: ObserversTuple, C: Corpus, - EM: EventManager, + EM: EventManager, { let (fitness, is_solution) = self.execute_input(&input, executor, manager)?; let observers = executor.observers(); @@ -490,7 +491,7 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - EM: EventManager, + EM: EventManager, { for entry in fs::read_dir(in_dir)? { let entry = entry?; @@ -532,7 +533,7 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - EM: EventManager, + EM: EventManager, { for in_dir in in_dirs { self.load_from_directory(executor, manager, in_dir)?; @@ -570,7 +571,7 @@ where E: Executor + HasObservers, OT: ObserversTuple, C: Corpus, - EM: EventManager, + EM: EventManager, { executor.pre_exec_observers()?; @@ -606,7 +607,7 @@ where C: Corpus, E: Executor + HasObservers, OT: ObserversTuple, - EM: EventManager, + EM: EventManager, { let mut added = 0; for _ in 0..num { diff --git a/libafl/src/utils.rs b/libafl/src/utils.rs index b0eff77df9..e0dd6dd201 100644 --- a/libafl/src/utils.rs +++ b/libafl/src/utils.rs @@ -1,7 +1,7 @@ //! Utility functions for AFL use core::{cell::RefCell, debug_assert, fmt::Debug, time}; -use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use xxhash_rust::xxh3::xxh3_64_with_seed; #[cfg(feature = "std")] From ff626a124bbeef90d16287679a0d9af110f48c64 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 22 Feb 2021 13:52:53 +0100 Subject: [PATCH 08/10] compiles --- libafl/src/corpus/mod.rs | 10 +-- libafl/src/events/logger.rs | 2 +- libafl/src/events/mod.rs | 2 +- libafl/src/executors/inprocess.rs | 6 +- libafl/src/mutators/mutations.rs | 105 +++++++++++++------------ libafl/src/mutators/scheduled.rs | 8 +- libafl/src/mutators/token_mutations.rs | 53 +++++++------ libafl/src/stages/mod.rs | 12 +-- libafl/src/stages/mutational.rs | 8 +- libafl/src/state/mod.rs | 9 +-- 10 files changed, 111 insertions(+), 104 deletions(-) diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 32069c5f46..1bea657106 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -41,21 +41,21 @@ where I: Input, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { + fn on_add(&self, _state: &mut S, _idx: usize, _testcase: &Testcase) -> Result<(), Error> { Ok(()) } /// Replaces the testcase at the given idx - fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { + fn on_replace(&self, _state: &mut S, _idx: usize, _testcase: &Testcase) -> Result<(), Error> { Ok(()) } /// Removes an entry from the corpus, returning it if it was present. fn on_remove( &self, - state: &mut S, - idx: usize, - testcase: &Option>, + _state: &mut S, + _idx: usize, + _testcase: &Option>, ) -> Result<(), Error> { Ok(()) } diff --git a/libafl/src/events/logger.rs b/libafl/src/events/logger.rs index 4262d847a3..ba3761ac32 100644 --- a/libafl/src/events/logger.rs +++ b/libafl/src/events/logger.rs @@ -31,7 +31,7 @@ where I: Input, ST: Stats, //CE: CustomEvent, { - fn process(&mut self, state: &mut S, executor: &mut E) -> Result + fn process(&mut self, state: &mut S, _executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 40e0fe05c6..d801f46aaa 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -202,7 +202,7 @@ impl EventManager for NopEventManager where I: Input, { - fn process(&mut self, state: &mut S, executor: &mut E) -> Result + fn process(&mut self, _state: &mut S, _executor: &mut E) -> Result where E: Executor + HasObservers, OT: ObserversTuple, diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 36972050c5..825e52ca73 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -249,7 +249,7 @@ pub mod unix_signals { .is_interesting_all(&input, observers, ExitKind::Crash) .expect("In crash handler objectives failure.".into()); if obj_fitness > 0 { - state.solutions_mut().add(Testcase::new(*input)); + state.solutions_mut().add(Testcase::new(input.clone())).expect("In crash handler solutions failure.".into()); mgr.fire( state, Event::Objective { @@ -270,7 +270,7 @@ pub mod unix_signals { unsafe fn inmem_handle_timeout( _sig: c_int, - info: siginfo_t, + _info: siginfo_t, _void: c_void, ) where EM: EventManager, @@ -302,7 +302,7 @@ pub mod unix_signals { .is_interesting_all(&input, observers, ExitKind::Crash) .expect("In timeout handler objectives failure.".into()); if obj_fitness > 0 { - state.solutions_mut().add(Testcase::new(*input)); + state.solutions_mut().add(Testcase::new(input.clone())).expect("In timeout handler solutions failure.".into()); mgr.fire( state, Event::Objective { diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index c2af06a1c2..ef45a83085 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -125,7 +125,7 @@ const INTERESTING_32: [i32; 27] = [ /// Bitflip mutation for inputs with a bytes vector pub fn mutation_bitflip( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -148,7 +148,7 @@ where pub fn mutation_byteflip( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -171,7 +171,7 @@ where pub fn mutation_byteinc( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -195,7 +195,7 @@ where pub fn mutation_bytedec( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -219,7 +219,7 @@ where pub fn mutation_byteneg( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -242,7 +242,7 @@ where pub fn mutation_byterand( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -265,7 +265,7 @@ where pub fn mutation_byteadd( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -293,7 +293,7 @@ where pub fn mutation_wordadd( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -323,7 +323,7 @@ where pub fn mutation_dwordadd( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -353,7 +353,7 @@ where pub fn mutation_qwordadd( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -383,7 +383,7 @@ where pub fn mutation_byteinteresting( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -407,7 +407,7 @@ where pub fn mutation_wordinteresting( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -437,7 +437,7 @@ where pub fn mutation_dwordinteresting( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -467,7 +467,7 @@ where pub fn mutation_bytesdelete( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -490,7 +490,7 @@ where pub fn mutation_bytesexpand( mutator: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -520,7 +520,7 @@ where pub fn mutation_bytesinsert( mutator: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -553,7 +553,7 @@ where pub fn mutation_bytesrandinsert( mutator: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -586,7 +586,7 @@ where pub fn mutation_bytesset( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -611,7 +611,7 @@ where pub fn mutation_bytesrandset( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -636,7 +636,7 @@ where pub fn mutation_bytescopy( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -661,7 +661,7 @@ where pub fn mutation_bytesswap( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -689,7 +689,7 @@ where /// Crossover insert mutation pub fn mutation_crossover_insert( mutator: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -703,18 +703,15 @@ where let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + let count = state.corpus().count(); + let idx = state.rand_mut().below(count as u64) as usize; if let Some(cur) = state.corpus().current() { if idx == *cur { return Ok(MutationResult::Skipped); } } - let other_testcase = state.corpus().get(idx)?; - let mut other_ref = other_testcase.borrow_mut(); - let other = other_ref.load_input()?; - - let other_size = other.bytes().len(); + let other_size = state.corpus().get(idx)?.borrow_mut().load_input()?.bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -723,6 +720,9 @@ where let to = state.rand_mut().below(size as u64) as usize; let mut len = state.rand_mut().below((other_size - from) as u64) as usize; + let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); + let other = other_testcase.load_input()?; + if size + len > mutator.max_size() { if mutator.max_size() > size { len = mutator.max_size() - size; @@ -741,7 +741,7 @@ where /// Crossover replace mutation pub fn mutation_crossover_replace( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -754,18 +754,15 @@ where let size = input.bytes().len(); // We don't want to use the testcase we're already using for splicing - let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + let count = state.corpus().count(); + let idx = state.rand_mut().below(count as u64) as usize; if let Some(cur) = state.corpus().current() { if idx == *cur { return Ok(MutationResult::Skipped); } } - let other_testcase = state.corpus().get(idx)?; - - let mut other_ref = other_testcase.borrow_mut(); - let other = other_ref.load_input()?; - - let other_size = other.bytes().len(); + + let other_size = state.corpus().get(idx)?.borrow_mut().load_input()?.bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -774,6 +771,9 @@ where let len = state.rand_mut().below(min(other_size - from, size) as u64) as usize; let to = state.rand_mut().below((size - len) as u64) as usize; + let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); + let other = other_testcase.load_input()?; + buffer_copy(input.bytes_mut(), other.bytes(), from, to, len); Ok(MutationResult::Mutated) @@ -798,7 +798,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { /// Splicing mutation from AFL pub fn mutation_splice( _: &M, - fuzzer: &F, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -809,33 +809,38 @@ where S: HasRand + HasCorpus, { // We don't want to use the testcase we're already using for splicing - let idx = state.rand_mut().below(state.corpus().count() as u64) as usize; + let count = state.corpus().count(); + let idx = state.rand_mut().below(count as u64) as usize; if let Some(cur) = state.corpus().current() { if idx == *cur { return Ok(MutationResult::Skipped); } } - let other_testcase = state.corpus().get(idx)?; - let mut other_ref = other_testcase.borrow_mut(); - let other = other_ref.load_input()?; + let (first_diff, last_diff) = { + let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); + let other = other_testcase.load_input()?; - let mut counter = 0; - let (first_diff, last_diff) = loop { - let (f, l) = locate_diffs(input.bytes(), other.bytes()); + let mut counter = 0; + loop { + let (f, l) = locate_diffs(input.bytes(), other.bytes()); - if f != l && f >= 0 && l >= 2 { - break (f, l); + if f != l && f >= 0 && l >= 2 { + break (f, l); + } + if counter == 3 { + return Ok(MutationResult::Skipped); + } + counter += 1; } - if counter == 3 { - return Ok(MutationResult::Skipped); - } - counter += 1; }; let split_at = state .rand_mut() .between(first_diff as u64, last_diff as u64) as usize; + + let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); + let other = other_testcase.load_input()?; input .bytes_mut() .splice(split_at.., other.bytes()[split_at..].iter().cloned()); diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index e8b880e3d9..2a3feeb1f7 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -117,12 +117,12 @@ where R: Rand, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, input: &I) -> u64 { + fn iterations(&self, state: &mut S, _: &I) -> u64 { 1 << (1 + state.rand_mut().below(6)) } /// Get the next mutation to apply - fn schedule(&self, mutations_count: usize, state: &mut S, input: &I) -> usize { + fn schedule(&self, mutations_count: usize, state: &mut S, _: &I) -> usize { debug_assert!(mutations_count > 0); state.rand_mut().below(mutations_count as u64) as usize } @@ -301,8 +301,8 @@ where scheduled.add_mutation(mutation_bytescopy); scheduled.add_mutation(mutation_bytesswap); - //scheduled.add_mutation(mutation_tokeninsert); - //scheduled.add_mutation(mutation_tokenreplace); + scheduled.add_mutation(mutation_tokeninsert); + scheduled.add_mutation(mutation_tokenreplace); scheduled.add_mutation(mutation_crossover_insert); scheduled.add_mutation(mutation_crossover_replace); diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index b86937b45f..505dc9d54b 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -30,8 +30,9 @@ impl TokensMetadata { } /// Insert a dictionary token -pub fn mutation_tokeninsert( - mutator: &mut M, +pub fn mutation_tokeninsert( + mutator: &M, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -41,22 +42,23 @@ where S: HasMetadata + HasRand, R: Rand, { - let meta; - match state.metadata().get::() { - Some(t) => { - meta = t; - } - None => { + let tokens_len = { + let meta = state.metadata().get::(); + if meta.is_none() { return Ok(MutationResult::Skipped); } + if meta.unwrap().tokens.len() == 0 { + return Ok(MutationResult::Skipped); + } + meta.unwrap().tokens.len() }; - if meta.tokens.len() == 0 { - return Ok(MutationResult::Skipped); - } - let token = &meta.tokens[state.rand_mut().below(meta.tokens.len() as u64) as usize]; - + let token_idx = state.rand_mut().below(tokens_len as u64) as usize; + let size = input.bytes().len(); let off = state.rand_mut().below((size + 1) as u64) as usize; + + let meta = state.metadata().get::().unwrap(); + let token = &meta.tokens[token_idx]; let mut len = token.len(); if size + len > mutator.max_size() { @@ -75,8 +77,9 @@ where } /// Overwrite with a dictionary token -pub fn mutation_tokenreplace( - _: &mut M, +pub fn mutation_tokenreplace( + _: &M, + _: &F, state: &mut S, input: &mut I, ) -> Result @@ -91,22 +94,22 @@ where return Ok(MutationResult::Skipped); } - let meta; - match state.metadata().get::() { - Some(t) => { - meta = t; - } - None => { + let tokens_len = { + let meta = state.metadata().get::(); + if meta.is_none() { return Ok(MutationResult::Skipped); } + if meta.unwrap().tokens.len() == 0 { + return Ok(MutationResult::Skipped); + } + meta.unwrap().tokens.len() }; - if meta.tokens.len() == 0 { - return Ok(MutationResult::Skipped); - } - let token = &meta.tokens[state.rand_mut().below(meta.tokens.len() as u64) as usize]; + let token_idx = state.rand_mut().below(tokens_len as u64) as usize; let off = state.rand_mut().below(size as u64) as usize; + let meta = state.metadata().get::().unwrap(); + let token = &meta.tokens[token_idx]; let mut len = token.len(); if off + len > size { len = size - off; diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 45c4db9b8d..27f88c1bfb 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -1,7 +1,7 @@ pub mod mutational; pub use mutational::StdMutationalStage; -use crate::{bolts::tuples::TupleList, corpus::Corpus, Error}; +use crate::{bolts::tuples::TupleList, Error}; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. @@ -31,11 +31,11 @@ pub trait StagesTuple { impl StagesTuple for () { fn perform_all( &self, - fuzzer: &F, - state: &mut S, - executor: &mut E, - manager: &mut EM, - corpus_idx: usize, + _: &F, + _: &mut S, + _: &mut E, + _: &mut EM, + _: usize, ) -> Result<(), Error> { Ok(()) } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index add170ba89..a77aaeb6e5 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -35,7 +35,7 @@ where fn mutator_mut(&mut self) -> &mut M; /// Gets the number of iterations this mutator should run for. - fn iterations(&mut self, state: &mut S) -> usize; + fn iterations(&self, state: &mut S) -> usize; /// Runs this (mutational) stage for the given testcase fn perform_mutational( @@ -54,12 +54,12 @@ where .borrow_mut() .load_input()? .clone(); - self.mutator_mut() + self.mutator() .mutate(fuzzer, state, &mut input_mut, i as i32)?; let fitness = state.evaluate_input(input_mut, executor, manager)?; - self.mutator_mut() + self.mutator() .post_exec(fuzzer, state, fitness, i as i32)?; } Ok(()) @@ -110,7 +110,7 @@ where } /// Gets the number of iterations as a random number - fn iterations(&mut self, state: &mut S) -> usize { + fn iterations(&self, state: &mut S) -> usize { 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize } } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index eddab4e503..38eb7b0c86 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -453,7 +453,7 @@ where self.solutions_mut().add(Testcase::new(input.clone()))?; } - if let idx = Some(self.add_if_interesting(&input, fitness)?) { + if !self.add_if_interesting(&input, fitness)?.is_none() { let observers_buf = manager.serialize_observers(observers)?; manager.fire( self, @@ -577,7 +577,7 @@ where executor.pre_exec(self, event_mgr, 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; executor.post_exec_observers()?; @@ -585,18 +585,17 @@ where let observers = executor.observers(); let fitness = self .feedbacks_mut() - .is_interesting_all(&input, observers, exit_kind)?; + .is_interesting_all(&input, observers, exit_kind.clone())?; let is_solution = self.objectives_mut() - .is_interesting_all(&input, observers, exit_kind.clone())? + .is_interesting_all(&input, observers, exit_kind)? > 0; Ok((fitness, is_solution)) } pub fn generate_initial_inputs( &mut self, - rand: &mut R, executor: &mut E, generator: &mut G, manager: &mut EM, From 3b0883721e795fe4b257424b943f9a8d9964fa3c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 22 Feb 2021 14:13:00 +0100 Subject: [PATCH 09/10] rand and queue corpus schedulers --- libafl/src/corpus/inmemory.rs | 98 ++++++++--------- libafl/src/corpus/mod.rs | 118 +++++++------------- libafl/src/corpus/queue.rs | 143 ++++++------------------- libafl/src/executors/inprocess.rs | 10 +- libafl/src/mutators/mutations.rs | 20 +++- libafl/src/mutators/token_mutations.rs | 2 +- libafl/src/stages/mod.rs | 11 +- libafl/src/stages/mutational.rs | 3 +- libafl/src/state/mod.rs | 14 +-- 9 files changed, 155 insertions(+), 264 deletions(-) diff --git a/libafl/src/corpus/inmemory.rs b/libafl/src/corpus/inmemory.rs index 83b63edfa1..22a28ff67a 100644 --- a/libafl/src/corpus/inmemory.rs +++ b/libafl/src/corpus/inmemory.rs @@ -1,74 +1,74 @@ //! In-memory corpus, keeps all test cases in memory at all times -use alloc::{borrow::ToOwned, vec::Vec}; -use core::{cell::RefCell, marker::PhantomData}; +use alloc::vec::Vec; +use core::cell::RefCell; use serde::{Deserialize, Serialize}; -use crate::{ - corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::Input, utils::Rand, Error, -}; +use crate::{corpus::Corpus, corpus::Testcase, inputs::Input, Error}; -/// A corpus handling all important fuzzing in memory. -#[derive(Serialize, Deserialize, Clone, Debug)] +/// A corpus handling all in memory. +#[derive(Default, Serialize, Deserialize, Clone, Debug)] #[serde(bound = "I: serde::de::DeserializeOwned")] -pub struct InMemoryCorpus +pub struct InMemoryCorpus where I: Input, - R: Rand, { entries: Vec>>, - pos: usize, - phantom: PhantomData, + current: Option, } -impl HasTestcaseVec for InMemoryCorpus +impl Corpus for InMemoryCorpus where I: Input, - R: Rand, { - fn entries(&self) -> &[RefCell>] { - &self.entries - } - fn entries_mut(&mut self) -> &mut Vec>> { - &mut self.entries - } -} - -impl Corpus for InMemoryCorpus -where - I: Input, - R: Rand, -{ - /// Gets the next entry + /// Returns the number of elements #[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 count(&self) -> usize { + self.entries.len() + } + + /// Add an entry to the corpus and return its index + #[inline] + fn add(&mut self, testcase: Testcase) -> Result { + self.entries.push(RefCell::new(testcase)); + Ok(self.entries.len() - 1) + } + + /// Replaces the testcase at the given idx + #[inline] + 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(()) + } + + /// Removes an entry from the corpus, returning it if it was present. + #[inline] + 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())) } } - /// Returns the testacase we currently use + /// Get by id #[inline] - fn current_testcase(&self) -> (&RefCell>, usize) { - (self.get(self.pos), self.pos) + fn get(&self, idx: usize) -> Result<&RefCell>, Error> { + Ok(&self.entries[idx]) } -} -impl InMemoryCorpus -where - I: Input, - R: Rand, -{ - pub fn new() -> Self { - Self { - entries: vec![], - pos: 0, - phantom: PhantomData, - } + /// 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 } } diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 1bea657106..6ed7f18bb1 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -3,11 +3,21 @@ pub mod testcase; pub use testcase::Testcase; -use alloc::vec::Vec; -use core::cell::RefCell; -use serde::{Deserialize, Serialize}; +pub mod inmemory; +pub use inmemory::InMemoryCorpus; -use crate::{inputs::Input, Error}; +pub mod queue; +pub use queue::QueueCorpusScheduler; + +use core::cell::RefCell; +use core::marker::PhantomData; + +use crate::{ + inputs::Input, + state::{HasCorpus, HasRand}, + utils::Rand, + Error, +}; /// Corpus with all current testcases pub trait Corpus: serde::Serialize + serde::de::DeserializeOwned @@ -46,7 +56,12 @@ where } /// Replaces the testcase at the given idx - fn on_replace(&self, _state: &mut S, _idx: usize, _testcase: &Testcase) -> Result<(), Error> { + fn on_replace( + &self, + _state: &mut S, + _idx: usize, + _testcase: &Testcase, + ) -> Result<(), Error> { Ok(()) } @@ -65,89 +80,34 @@ where fn next(&self, state: &mut S) -> Result; } -/* -pub struct RandCorpusScheduler {} +pub struct RandCorpusScheduler +where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand, +{ + phantom: PhantomData<(C, I, R, S)>, +} -impl CorpusScheduler for RandCorpusScheduler { +impl CorpusScheduler for RandCorpusScheduler +where + S: HasCorpus + HasRand, + C: Corpus, + I: Input, + R: Rand, +{ /// Gets the next entry at random - fn next(state: &mut S) -> Result - where - S: HasCorpus + HasRand, - C: Corpus, - I: Input, - R: Rand, - { + fn next(&self, state: &mut S) -> Result { if state.corpus().count() == 0 { Err(Error::Empty("No entries in corpus".to_owned())) } else { let len = state.corpus().count(); let id = state.rand_mut().below(len as u64) as usize; + *state.corpus_mut().current_mut() = Some(id); Ok(id) } } } -*/ -#[derive(Default, Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "I: serde::de::DeserializeOwned")] -pub struct InMemoryCorpus -where - I: Input, -{ - entries: Vec>>, - current: Option, -} - -impl Corpus for InMemoryCorpus -where - I: Input, -{ - /// Returns the number of elements - #[inline] - fn count(&self) -> usize { - self.entries.len() - } - - /// Add an entry to the corpus and return its index - #[inline] - fn add(&mut self, testcase: Testcase) -> Result { - self.entries.push(RefCell::new(testcase)); - Ok(self.entries.len() - 1) - } - - /// Replaces the testcase at the given idx - #[inline] - 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(()) - } - - /// Removes an entry from the corpus, returning it if it was present. - #[inline] - fn remove(&mut self, idx: usize) -> Result>, Error> { - if idx >= self.entries.len() { - Ok(None) - } else { - Ok(Some(self.entries.remove(idx).into_inner())) - } - } - - /// Get by id - #[inline] - fn get(&self, idx: usize) -> Result<&RefCell>, Error> { - Ok(&self.entries[idx]) - } - - /// Current testcase scheduled - fn current(&self) -> &Option { - &self.current - } - - /// Current testcase scheduled (mut) - fn current_mut(&mut self) -> &mut Option { - &mut self.current - } -} +pub type StdCorpusScheduler = RandCorpusScheduler; diff --git a/libafl/src/corpus/queue.rs b/libafl/src/corpus/queue.rs index 1e90a6e0ce..12fa682e14 100644 --- a/libafl/src/corpus/queue.rs +++ b/libafl/src/corpus/queue.rs @@ -1,132 +1,52 @@ //! The queue corpus implements an afl-like queue mechanism -use alloc::{borrow::ToOwned, vec::Vec}; -use core::{cell::RefCell, marker::PhantomData}; -use serde::{Deserialize, Serialize}; +use alloc::borrow::ToOwned; +use core::marker::PhantomData; use crate::{ - corpus::Corpus, corpus::HasTestcaseVec, corpus::Testcase, inputs::Input, utils::Rand, Error, + corpus::{Corpus, CorpusScheduler}, + inputs::Input, + state::HasCorpus, + Error, }; -/// A Queue-like corpus, wrapping an existing Corpus instance -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "I: serde::de::DeserializeOwned")] -pub struct QueueCorpus +pub struct QueueCorpusScheduler where - C: Corpus, + S: HasCorpus, + C: Corpus, I: Input, - R: Rand, { - corpus: C, - pos: usize, - cycles: u64, - phantom: PhantomData<(I, R)>, + phantom: PhantomData<(C, I, S)>, } -impl HasTestcaseVec for QueueCorpus +impl CorpusScheduler for QueueCorpusScheduler where - C: Corpus, + S: HasCorpus, + C: Corpus, I: Input, - R: Rand, { - #[inline] - fn entries(&self) -> &[RefCell>] { - self.corpus.entries() - } - #[inline] - fn entries_mut(&mut self) -> &mut Vec>> { - self.corpus.entries_mut() - } -} - -impl Corpus for QueueCorpus -where - C: Corpus, - I: Input, - R: Rand, -{ - /// Returns the number of elements - #[inline] - fn count(&self) -> usize { - self.corpus.count() - } - - #[inline] - fn add(&mut self, entry: Testcase) -> usize { - self.corpus.add(entry) - } - - /// Removes an entry from the corpus, returning it if it was present. - #[inline] - fn remove(&mut self, entry: &Testcase) -> Option> { - self.corpus.remove(entry) - } - - /// Gets a random entry - #[inline] - fn random_entry(&self, rand: &mut R) -> Result<(&RefCell>, usize), Error> { - self.corpus.random_entry(rand) - } - - /// Returns the testacase we currently use - #[inline] - fn current_testcase(&self) -> (&RefCell>, usize) { - (self.get(self.pos - 1), self.pos - 1) - } - - /// Gets the next entry - #[inline] - fn next(&mut self, _rand: &mut R) -> Result<(&RefCell>, usize), Error> { - self.pos += 1; - if self.corpus.count() == 0 { - return Err(Error::Empty("Corpus".to_owned())); - } - if self.pos > self.corpus.count() { - // TODO: Always loop or return informational error? - self.pos = 1; - self.cycles += 1; - } - Ok((&self.corpus.entries()[self.pos - 1], self.pos - 1)) - } -} - -impl QueueCorpus -where - C: Corpus, - I: Input, - R: Rand, -{ - pub fn new(corpus: C) -> Self { - Self { - corpus: corpus, - phantom: PhantomData, - cycles: 0, - pos: 0, + /// Gets the next entry at random + fn next(&self, state: &mut S) -> Result { + if state.corpus().count() == 0 { + Err(Error::Empty("No entries in corpus".to_owned())) + } else { + let id = match state.corpus().current() { + Some(cur) => { + if *cur + 1 > state.corpus().count() { + 0 + } else { + *cur + 1 + } + } + None => 0, + }; + *state.corpus_mut().current_mut() = Some(id); + Ok(id) } } - - #[inline] - pub fn cycles(&self) -> u64 { - self.cycles - } - - #[inline] - pub fn pos(&self) -> usize { - self.pos - } - - // TODO maybe impl HasCorpus - #[inline] - pub fn corpus(&self) -> &C { - &self.corpus - } - - #[inline] - pub fn corpus_mut(&mut self) -> &mut C { - &mut self.corpus - } } +/* #[cfg(test)] #[cfg(feature = "std")] mod tests { @@ -170,3 +90,4 @@ mod tests { assert_eq!(filename, "fancyfile"); } } +*/ diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 825e52ca73..65222ab004 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -249,7 +249,10 @@ pub mod unix_signals { .is_interesting_all(&input, observers, ExitKind::Crash) .expect("In crash handler objectives failure.".into()); if obj_fitness > 0 { - state.solutions_mut().add(Testcase::new(input.clone())).expect("In crash handler solutions failure.".into()); + state + .solutions_mut() + .add(Testcase::new(input.clone())) + .expect("In crash handler solutions failure.".into()); mgr.fire( state, Event::Objective { @@ -302,7 +305,10 @@ pub mod unix_signals { .is_interesting_all(&input, observers, ExitKind::Crash) .expect("In timeout handler objectives failure.".into()); if obj_fitness > 0 { - state.solutions_mut().add(Testcase::new(input.clone())).expect("In timeout handler solutions failure.".into()); + state + .solutions_mut() + .add(Testcase::new(input.clone())) + .expect("In timeout handler solutions failure.".into()); mgr.fire( state, Event::Objective { diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index ef45a83085..730efad2a1 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -711,7 +711,13 @@ where } } - let other_size = state.corpus().get(idx)?.borrow_mut().load_input()?.bytes().len(); + let other_size = state + .corpus() + .get(idx)? + .borrow_mut() + .load_input()? + .bytes() + .len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -761,8 +767,14 @@ where return Ok(MutationResult::Skipped); } } - - let other_size = state.corpus().get(idx)?.borrow_mut().load_input()?.bytes().len(); + + let other_size = state + .corpus() + .get(idx)? + .borrow_mut() + .load_input()? + .bytes() + .len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -838,7 +850,7 @@ where let split_at = state .rand_mut() .between(first_diff as u64, last_diff as u64) as usize; - + let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); let other = other_testcase.load_input()?; input diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 505dc9d54b..252b17fcfb 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -53,7 +53,7 @@ where meta.unwrap().tokens.len() }; let token_idx = state.rand_mut().below(tokens_len as u64) as usize; - + let size = input.bytes().len(); let off = state.rand_mut().below((size + 1) as u64) as usize; diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index 27f88c1bfb..01e729ac0f 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -1,7 +1,7 @@ pub mod mutational; pub use mutational::StdMutationalStage; -use crate::{bolts::tuples::TupleList, Error}; +use crate::{bolts::tuples::TupleList, Error}; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. @@ -29,14 +29,7 @@ pub trait StagesTuple { } impl StagesTuple for () { - fn perform_all( - &self, - _: &F, - _: &mut S, - _: &mut E, - _: &mut EM, - _: usize, - ) -> Result<(), Error> { + fn perform_all(&self, _: &F, _: &mut S, _: &mut E, _: &mut EM, _: usize) -> Result<(), Error> { Ok(()) } } diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index a77aaeb6e5..d69c2e3600 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -59,8 +59,7 @@ where let fitness = state.evaluate_input(input_mut, executor, manager)?; - self.mutator() - .post_exec(fuzzer, state, fitness, i as i32)?; + self.mutator().post_exec(fuzzer, state, fitness, i as i32)?; } Ok(()) } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 38eb7b0c86..0bdc3dd1d1 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -583,14 +583,14 @@ where executor.post_exec_observers()?; let observers = executor.observers(); - let fitness = self - .feedbacks_mut() - .is_interesting_all(&input, observers, exit_kind.clone())?; + let fitness = + self.feedbacks_mut() + .is_interesting_all(&input, observers, exit_kind.clone())?; - let is_solution = - self.objectives_mut() - .is_interesting_all(&input, observers, exit_kind)? - > 0; + let is_solution = self + .objectives_mut() + .is_interesting_all(&input, observers, exit_kind)? + > 0; Ok((fitness, is_solution)) } From a5cc8313dbf8cc27eea10cc41a67ca1e6bbdc7f9 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 22 Feb 2021 15:19:35 +0100 Subject: [PATCH 10/10] new ondisk corpus --- fuzzers/libfuzzer_libpng/src/mod.rs | 15 ++-- libafl/src/corpus/inmemory.rs | 12 +++ libafl/src/corpus/mod.rs | 19 +++++ libafl/src/corpus/ondisk.rs | 98 +++++++++++------------ libafl/src/corpus/queue.rs | 13 ++++ libafl/src/executors/inprocess.rs | 25 ++---- libafl/src/fuzzer.rs | 30 ++++--- libafl/src/mutators/mod.rs | 6 +- libafl/src/mutators/mutations.rs | 104 ++++++++++++------------- libafl/src/mutators/scheduled.rs | 76 +++++++----------- libafl/src/mutators/token_mutations.rs | 6 +- libafl/src/stages/mod.rs | 45 +++++++---- libafl/src/stages/mutational.rs | 34 ++++---- 13 files changed, 260 insertions(+), 223 deletions(-) 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,