diff --git a/fuzzers/baby_fuzzer_grimoire/src/main.rs b/fuzzers/baby_fuzzer_grimoire/src/main.rs index e275c96c5f..ed26dd0e9f 100644 --- a/fuzzers/baby_fuzzer_grimoire/src/main.rs +++ b/fuzzers/baby_fuzzer_grimoire/src/main.rs @@ -9,7 +9,7 @@ use libafl::{ executors::{inprocess::InProcessExecutor, ExitKind}, feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Evaluator, Fuzzer, StdFuzzer}, - inputs::{GeneralizedInput, HasTargetBytes}, + inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator, @@ -59,13 +59,13 @@ pub fn main() { let mut file = fs::File::open(path).expect("no file found"); let mut buffer = vec![]; file.read_to_end(&mut buffer).expect("buffer overflow"); - let input = GeneralizedInput::new(buffer); + let input = BytesInput::new(buffer); initial_inputs.push(input); } } // The closure that we want to fuzz - let mut harness = |input: &GeneralizedInput| { + let mut harness = |input: &BytesInput| { let target_bytes = input.target_bytes(); let bytes = target_bytes.as_slice(); @@ -77,12 +77,6 @@ pub fn main() { signals_set(3); } - unsafe { - if input.grimoire_mutated { - // println!(">>> {:?}", input.generalized()); - println!(">>> {:?}", std::str::from_utf8_unchecked(bytes)); - } - } signals_set(1); ExitKind::Ok }; @@ -158,7 +152,7 @@ pub fn main() { let mut stages = tuple_list!( generalization, StdMutationalStage::new(mutator), - StdMutationalStage::new(grimoire_mutator) + StdMutationalStage::transforming(grimoire_mutator) ); for input in initial_inputs { diff --git a/fuzzers/fuzzbench_text/src/lib.rs b/fuzzers/fuzzbench_text/src/lib.rs index a1436cc8ba..cc188656f5 100644 --- a/fuzzers/fuzzbench_text/src/lib.rs +++ b/fuzzers/fuzzbench_text/src/lib.rs @@ -31,7 +31,7 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, - inputs::{BytesInput, GeneralizedInput, HasTargetBytes}, + inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ grimoire::{ @@ -47,8 +47,8 @@ use libafl::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, stages::{ - calibrate::CalibrationStage, dump::DumpToDiskStage, power::StdPowerMutationalStage, - GeneralizationStage, StdMutationalStage, TracingStage, + calibrate::CalibrationStage, power::StdPowerMutationalStage, GeneralizationStage, + StdMutationalStage, TracingStage, }, state::{HasCorpus, HasMetadata, StdState}, Error, @@ -148,11 +148,8 @@ pub fn libafl_main() { } } let mut crashes = out_dir.clone(); - let mut report = out_dir.clone(); crashes.push("crashes"); - report.push("report"); out_dir.push("queue"); - drop(fs::create_dir(&report)); let in_dir = PathBuf::from( res.get_one::("in") @@ -177,10 +174,8 @@ pub fn libafl_main() { ); if check_if_textual(&in_dir, &tokens) { - fuzz_text( - out_dir, crashes, &report, &in_dir, tokens, &logfile, timeout, - ) - .expect("An error occurred while fuzzing"); + fuzz_text(out_dir, crashes, &in_dir, tokens, &logfile, timeout) + .expect("An error occurred while fuzzing"); } else { fuzz_binary(out_dir, crashes, &in_dir, tokens, &logfile, timeout) .expect("An error occurred while fuzzing"); @@ -466,7 +461,6 @@ fn fuzz_binary( fn fuzz_text( corpus_dir: PathBuf, objective_dir: PathBuf, - report_dir: &Path, seed_dir: &PathBuf, tokenfile: Option, logfile: &PathBuf, @@ -586,7 +580,7 @@ fn fuzz_text( ), 3, ); - let grimoire = StdMutationalStage::new(grimoire_mutator); + let grimoire = StdMutationalStage::transforming(grimoire_mutator); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( @@ -597,7 +591,7 @@ fn fuzz_text( let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); // The wrapped harness function, calling out to the LLVM-style harness - let mut harness = |input: &GeneralizedInput| { + let mut harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target.as_slice(); libfuzzer_test_one_input(buf); @@ -633,23 +627,8 @@ fn fuzz_text( timeout * 10, )); - let fuzzbench = DumpToDiskStage::new( - |input: &GeneralizedInput| input.target_bytes().into(), - &report_dir.join("queue"), - &report_dir.join("crashes"), - ) - .unwrap(); - // The order of the stages matter! - let mut stages = tuple_list!( - fuzzbench, - generalization, - calibration, - tracing, - i2s, - power, - grimoire - ); + let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire); // Read tokens if state.metadata().get::().is_none() { diff --git a/fuzzers/tutorial/src/mutator.rs b/fuzzers/tutorial/src/mutator.rs index 19647003ee..6ae72af90f 100644 --- a/fuzzers/tutorial/src/mutator.rs +++ b/fuzzers/tutorial/src/mutator.rs @@ -4,7 +4,6 @@ use libafl::{ rands::{Rand, StdRand}, tuples::Named, }, - inputs::UsesInput, mutators::{MutationResult, Mutator}, state::HasRand, Error, @@ -16,9 +15,9 @@ pub struct LainMutator { inner: lain::mutator::Mutator, } -impl Mutator for LainMutator +impl Mutator for LainMutator where - S: UsesInput + HasRand, + S: HasRand, { fn mutate( &mut self, diff --git a/libafl/src/generators/mod.rs b/libafl/src/generators/mod.rs index d8d92ca8b1..6a7dbe1c13 100644 --- a/libafl/src/generators/mod.rs +++ b/libafl/src/generators/mod.rs @@ -5,7 +5,7 @@ use core::{cmp::min, marker::PhantomData}; use crate::{ bolts::rands::Rand, - inputs::{bytes::BytesInput, GeneralizedInput, Input}, + inputs::{bytes::BytesInput, Input}, state::HasRand, Error, }; @@ -33,51 +33,6 @@ where fn generate_dummy(&self, state: &mut S) -> I; } -/// A Generator that produces [`GeneralizedInput`]s from a wrapped [`BytesInput`] generator -#[derive(Clone, Debug)] -pub struct GeneralizedInputBytesGenerator { - bytes_generator: G, - phantom: PhantomData, -} - -impl GeneralizedInputBytesGenerator -where - S: HasRand, - G: Generator, -{ - /// Creates a new [`GeneralizedInputBytesGenerator`] by wrapping a bytes generator. - pub fn new(bytes_generator: G) -> Self { - Self { - bytes_generator, - phantom: PhantomData, - } - } -} - -impl From for GeneralizedInputBytesGenerator -where - S: HasRand, - G: Generator, -{ - fn from(bytes_generator: G) -> Self { - Self::new(bytes_generator) - } -} - -impl Generator for GeneralizedInputBytesGenerator -where - S: HasRand, - G: Generator, -{ - fn generate(&mut self, state: &mut S) -> Result { - Ok(self.bytes_generator.generate(state)?.into()) - } - - fn generate_dummy(&self, state: &mut S) -> GeneralizedInput { - self.bytes_generator.generate_dummy(state).into() - } -} - #[derive(Clone, Debug)] /// Generates random bytes pub struct RandBytesGenerator diff --git a/libafl/src/inputs/generalized.rs b/libafl/src/inputs/generalized.rs index a32040b9c2..8fa46021fd 100644 --- a/libafl/src/inputs/generalized.rs +++ b/libafl/src/inputs/generalized.rs @@ -1,18 +1,16 @@ //! The `GeneralizedInput` is an input that ca be generalized to represent a rule, used by Grimoire -use alloc::{borrow::ToOwned, rc::Rc, string::String, vec::Vec}; -use core::{cell::RefCell, convert::From, hash::Hasher}; -#[cfg(feature = "std")] -use std::{fs::File, io::Read, path::Path}; +use alloc::vec::Vec; -use ahash::AHasher; use serde::{Deserialize, Serialize}; -#[cfg(feature = "std")] -use crate::Error; use crate::{ - bolts::{ownedref::OwnedSlice, HasLen}, - inputs::{BytesInput, HasBytesVec, HasTargetBytes, Input}, + corpus::{Corpus, CorpusId, Testcase}, + impl_serdeany, + inputs::BytesInput, + stages::mutational::{MutatedTransform, MutatedTransformPost}, + state::{HasCorpus, HasMetadata}, + Error, }; /// An item of the generalized input @@ -24,142 +22,31 @@ pub enum GeneralizedItem { Gap, } -/// A bytes input with a generalized version mainly used for Grimoire +/// Metadata regarding the generalised content of an input #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct GeneralizedInput { - /// The raw input bytes - bytes: Vec, - generalized: Option>, - /// If was mutated or not by Grimoire - pub grimoire_mutated: bool, +pub struct GeneralizedInputMetadata { + generalized: Vec, } -impl Input for GeneralizedInput { - /// Generate a name for this input - fn generate_name(&self, _idx: usize) -> String { - let mut hasher = AHasher::new_with_keys(0, 0); - // TODO add generalized - hasher.write(self.bytes()); - format!("{:016x}", hasher.finish()) - } - - /// Load from a plain file of bytes - #[cfg(feature = "std")] - fn from_file

(path: P) -> Result - where - P: AsRef, - { - let mut file = File::open(path)?; - let mut bytes: Vec = vec![]; - file.read_to_end(&mut bytes)?; - Ok(Self { - bytes, - generalized: None, - grimoire_mutated: false, - }) - } - - /// An hook executed before being added to the corpus - fn wrapped_as_testcase(&mut self) { - // remove generalized for inputs generated with bit-level mutations - // and fix bytes for the ones generated by grimoire - if self.grimoire_mutated { - self.bytes = self.generalized_to_bytes(); - } else { - self.generalized = None; - } - // restore to allow bit-level mutations - self.grimoire_mutated = false; - } -} - -/// Rc Ref-cell from Input -impl From for Rc> { - fn from(input: GeneralizedInput) -> Self { - Rc::new(RefCell::new(input)) - } -} - -impl HasBytesVec for GeneralizedInput { - #[inline] - fn bytes(&self) -> &[u8] { - &self.bytes - } - - #[inline] - fn bytes_mut(&mut self) -> &mut Vec { - &mut self.bytes - } -} - -impl HasTargetBytes for GeneralizedInput { - #[inline] - fn target_bytes(&self) -> OwnedSlice { - if self.grimoire_mutated { - OwnedSlice::from(self.generalized_to_bytes()) - } else { - OwnedSlice::from(&self.bytes) - } - } -} - -impl HasLen for GeneralizedInput { - #[inline] - fn len(&self) -> usize { - self.bytes.len() - } -} - -impl From> for GeneralizedInput { - fn from(bytes: Vec) -> Self { - Self::new(bytes) - } -} - -impl From<&[u8]> for GeneralizedInput { - fn from(bytes: &[u8]) -> Self { - Self::new(bytes.to_owned()) - } -} - -impl From for GeneralizedInput { - fn from(bytes_input: BytesInput) -> Self { - Self::new(bytes_input.bytes) - } -} - -impl From<&BytesInput> for GeneralizedInput { - fn from(bytes_input: &BytesInput) -> Self { - bytes_input.bytes().into() - } -} - -impl GeneralizedInput { - /// Creates a new bytes input using the given bytes - #[must_use] - pub fn new(bytes: Vec) -> Self { - Self { - bytes, - generalized: None, - grimoire_mutated: false, - } - } +impl_serdeany!(GeneralizedInputMetadata); +impl GeneralizedInputMetadata { /// Fill the generalized vector from a slice of option (None -> Gap) - pub fn generalized_from_options(&mut self, v: &[Option]) { - let mut res = vec![]; + #[must_use] + pub fn generalized_from_options(v: &[Option]) -> Self { + let mut generalized = vec![]; let mut bytes = vec![]; if v.first() != Some(&None) { - res.push(GeneralizedItem::Gap); + generalized.push(GeneralizedItem::Gap); } for e in v { match e { None => { if !bytes.is_empty() { - res.push(GeneralizedItem::Bytes(bytes.clone())); + generalized.push(GeneralizedItem::Bytes(bytes.clone())); bytes.clear(); } - res.push(GeneralizedItem::Gap); + generalized.push(GeneralizedItem::Gap); } Some(b) => { bytes.push(*b); @@ -167,71 +54,93 @@ impl GeneralizedInput { } } if !bytes.is_empty() { - res.push(GeneralizedItem::Bytes(bytes)); + generalized.push(GeneralizedItem::Bytes(bytes)); } - if res.last() != Some(&GeneralizedItem::Gap) { - res.push(GeneralizedItem::Gap); - } - self.generalized = Some(res); - } - - /// Extend the generalized input - pub fn generalized_extend(&mut self, other: &[GeneralizedItem]) { - let gen = self.generalized.get_or_insert_with(Vec::new); - if gen.last().is_some() - && other.first().is_some() - && *gen.last().unwrap() == GeneralizedItem::Gap - && *other.first().unwrap() == GeneralizedItem::Gap - { - gen.extend_from_slice(&other[1..]); - } else { - gen.extend_from_slice(other); + if generalized.last() != Some(&GeneralizedItem::Gap) { + generalized.push(GeneralizedItem::Gap); } + Self { generalized } } /// Get the size of the generalized #[must_use] pub fn generalized_len(&self) -> usize { - match &self.generalized { - None => 0, - Some(gen) => { - let mut size = 0; - for item in gen { - match item { - GeneralizedItem::Bytes(b) => size += b.len(), - GeneralizedItem::Gap => size += 1, - } - } - size + let mut size = 0; + for item in &self.generalized { + match item { + GeneralizedItem::Bytes(b) => size += b.len(), + GeneralizedItem::Gap => size += 1, } } + size } /// Convert generalized to bytes #[must_use] pub fn generalized_to_bytes(&self) -> Vec { - match &self.generalized { - None => vec![], - Some(gen) => { - let mut bytes = vec![]; - for item in gen { - if let GeneralizedItem::Bytes(b) = item { - bytes.extend_from_slice(b); - } - } - bytes - } - } + self.generalized + .iter() + .filter_map(|item| match item { + GeneralizedItem::Bytes(bytes) => Some(bytes), + GeneralizedItem::Gap => None, + }) + .flatten() + .copied() + .collect() } /// Get the generalized input #[must_use] - pub fn generalized(&self) -> Option<&[GeneralizedItem]> { - self.generalized.as_deref() + pub fn generalized(&self) -> &[GeneralizedItem] { + &self.generalized } /// Get the generalized input (mutable) - pub fn generalized_mut(&mut self) -> &mut Option> { + pub fn generalized_mut(&mut self) -> &mut Vec { &mut self.generalized } } + +impl MutatedTransform for GeneralizedInputMetadata +where + S: HasCorpus, +{ + type Post = Self; + + fn try_transform_from( + base: &Testcase, + _state: &S, + corpus_idx: CorpusId, + ) -> Result { + base.metadata() + .get::() + .ok_or_else(|| { + Error::key_not_found(format!( + "Couldn't find the GeneralizedInputMetadata for corpus entry {corpus_idx}", + )) + }) + .cloned() + } + + fn try_transform_into(self, _state: &S) -> Result<(BytesInput, Self::Post), Error> { + Ok((BytesInput::from(self.generalized_to_bytes()), self)) + } +} + +impl MutatedTransformPost for GeneralizedInputMetadata +where + S: HasCorpus, +{ + fn post_exec( + self, + state: &mut S, + _stage_idx: i32, + corpus_idx: Option, + ) -> Result<(), Error> { + if let Some(corpus_idx) = corpus_idx { + let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); + testcase.metadata_mut().insert(self); + } + Ok(()) + } +} diff --git a/libafl/src/mutators/encoded_mutations.rs b/libafl/src/mutators/encoded_mutations.rs index 9273ae38d8..276a237e96 100644 --- a/libafl/src/mutators/encoded_mutations.rs +++ b/libafl/src/mutators/encoded_mutations.rs @@ -23,7 +23,7 @@ use crate::{ #[derive(Debug, Default)] pub struct EncodedRandMutator; -impl> Mutator for EncodedRandMutator { +impl Mutator for EncodedRandMutator { fn mutate( &mut self, state: &mut S, @@ -58,7 +58,7 @@ impl EncodedRandMutator { #[derive(Debug, Default)] pub struct EncodedIncMutator; -impl> Mutator for EncodedIncMutator { +impl Mutator for EncodedIncMutator { fn mutate( &mut self, state: &mut S, @@ -93,7 +93,7 @@ impl EncodedIncMutator { #[derive(Debug, Default)] pub struct EncodedDecMutator; -impl> Mutator for EncodedDecMutator { +impl Mutator for EncodedDecMutator { fn mutate( &mut self, state: &mut S, @@ -128,7 +128,7 @@ impl EncodedDecMutator { #[derive(Debug, Default)] pub struct EncodedAddMutator; -impl> Mutator for EncodedAddMutator { +impl Mutator for EncodedAddMutator { fn mutate( &mut self, state: &mut S, @@ -167,7 +167,7 @@ impl EncodedAddMutator { #[derive(Debug, Default)] pub struct EncodedDeleteMutator; -impl> Mutator for EncodedDeleteMutator { +impl Mutator for EncodedDeleteMutator { fn mutate( &mut self, state: &mut S, @@ -207,9 +207,9 @@ pub struct EncodedInsertCopyMutator { tmp_buf: Vec, } -impl Mutator for EncodedInsertCopyMutator +impl Mutator for EncodedInsertCopyMutator where - S: UsesInput + HasRand + HasMaxSize, + S: HasRand + HasMaxSize, { fn mutate( &mut self, @@ -268,7 +268,7 @@ impl EncodedInsertCopyMutator { #[derive(Debug, Default)] pub struct EncodedCopyMutator; -impl + HasRand> Mutator for EncodedCopyMutator { +impl Mutator for EncodedCopyMutator { fn mutate( &mut self, state: &mut S, @@ -308,7 +308,7 @@ impl EncodedCopyMutator { #[derive(Debug, Default)] pub struct EncodedCrossoverInsertMutator; -impl Mutator for EncodedCrossoverInsertMutator +impl Mutator for EncodedCrossoverInsertMutator where S: UsesInput + HasRand + HasCorpus + HasMaxSize, { @@ -381,7 +381,7 @@ impl EncodedCrossoverInsertMutator { #[derive(Debug, Default)] pub struct EncodedCrossoverReplaceMutator; -impl Mutator for EncodedCrossoverReplaceMutator +impl Mutator for EncodedCrossoverReplaceMutator where S: UsesInput + HasRand + HasCorpus, { diff --git a/libafl/src/mutators/gramatron.rs b/libafl/src/mutators/gramatron.rs index a1898dcbec..caac9a9fcd 100644 --- a/libafl/src/mutators/gramatron.rs +++ b/libafl/src/mutators/gramatron.rs @@ -10,7 +10,7 @@ use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, generators::GramatronGenerator, - inputs::{GramatronInput, Terminal, UsesInput}, + inputs::{GramatronInput, Terminal}, mutators::{MutationResult, Mutator}, random_corpus_id, state::{HasCorpus, HasMetadata, HasRand}, @@ -28,9 +28,9 @@ where generator: &'a GramatronGenerator<'a, S>, } -impl<'a, S> Mutator for GramatronRandomMutator<'a, S> +impl<'a, S> Mutator for GramatronRandomMutator<'a, S> where - S: UsesInput + HasRand + HasMetadata, + S: HasRand + HasMetadata, { fn mutate( &mut self, @@ -97,9 +97,9 @@ impl GramatronIdxMapMetadata { #[derive(Default, Debug)] pub struct GramatronSpliceMutator; -impl Mutator for GramatronSpliceMutator +impl Mutator for GramatronSpliceMutator where - S: UsesInput + HasRand + HasCorpus + HasMetadata, + S: HasRand + HasCorpus + HasMetadata, { fn mutate( &mut self, @@ -169,9 +169,9 @@ pub struct GramatronRecursionMutator { feature: Vec, } -impl Mutator for GramatronRecursionMutator +impl Mutator for GramatronRecursionMutator where - S: UsesInput + HasRand + HasMetadata, + S: HasRand + HasMetadata, { fn mutate( &mut self, diff --git a/libafl/src/mutators/grimoire.rs b/libafl/src/mutators/grimoire.rs index b9c58211a0..a86f337b8a 100644 --- a/libafl/src/mutators/grimoire.rs +++ b/libafl/src/mutators/grimoire.rs @@ -7,7 +7,7 @@ use core::cmp::{max, min}; use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, - inputs::{GeneralizedInput, GeneralizedItem, UsesInput}, + inputs::{GeneralizedInputMetadata, GeneralizedItem}, mutators::{token_mutations::Tokens, MutationResult, Mutator}, stages::generalization::GeneralizedIndexesMetadata, state::{HasCorpus, HasMetadata, HasRand}, @@ -24,7 +24,7 @@ fn extend_with_random_generalized( gap_indices: &mut Vec, ) -> Result<(), Error> where - S: HasMetadata + HasRand + HasCorpus, + S: HasMetadata + HasRand + HasCorpus, { let rand_idx = state.rand_mut().next() as usize; @@ -40,50 +40,42 @@ where .unwrap() }; - /*if state - .corpus() - .get(idx)? - .borrow_mut() - .load_input()? - .generalized() - .is_none() - { - return Ok(true); - }*/ - if state.rand_mut().below(100) > CHOOSE_SUBINPUT_PROB { if state.rand_mut().below(100) < 50 { let rand1 = state.rand_mut().next() as usize; let rand2 = state.rand_mut().next() as usize; let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); - let other = other_testcase.load_input()?; + if let Some(other) = other_testcase + .metadata_mut() + .get::() + { + if other.generalized_len() > 0 { + let gen = other.generalized(); - if other.generalized_len() > 0 { - let gen = other.generalized().unwrap(); + for (i, _) in gen + .iter() + .enumerate() + .filter(|&(_, x)| *x == GeneralizedItem::Gap) + { + gap_indices.push(i); + } + let min_idx = gap_indices[rand1 % gap_indices.len()]; + let max_idx = gap_indices[rand2 % gap_indices.len()]; + let (mut min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx)); - for (i, _) in gen - .iter() - .enumerate() - .filter(|&(_, x)| *x == GeneralizedItem::Gap) - { - gap_indices.push(i); + gap_indices.clear(); + + if items.last() == Some(&GeneralizedItem::Gap) { + min_idx += 1; + } + items.extend_from_slice(&gen[min_idx..=max_idx]); + + debug_assert!(items.first() == Some(&GeneralizedItem::Gap)); + debug_assert!(items.last() == Some(&GeneralizedItem::Gap)); + + return Ok(()); } - let min_idx = gap_indices[rand1 % gap_indices.len()]; - let max_idx = gap_indices[rand2 % gap_indices.len()]; - let (mut min_idx, max_idx) = (min(min_idx, max_idx), max(min_idx, max_idx)); - - gap_indices.clear(); - - if items.last() == Some(&GeneralizedItem::Gap) { - min_idx += 1; - } - items.extend_from_slice(&gen[min_idx..=max_idx]); - - debug_assert!(items.first() == Some(&GeneralizedItem::Gap)); - debug_assert!(items.last() == Some(&GeneralizedItem::Gap)); - - return Ok(()); } } @@ -107,8 +99,11 @@ where } let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); - let other = other_testcase.load_input()?; - let gen = other.generalized().unwrap(); + let other = other_testcase + .metadata_mut() + .get::() + .unwrap(); + let gen = other.generalized(); if items.last() == Some(&GeneralizedItem::Gap) && gen.first() == Some(&GeneralizedItem::Gap) { items.extend_from_slice(&gen[1..]); @@ -128,27 +123,22 @@ pub struct GrimoireExtensionMutator { gap_indices: Vec, } -impl Mutator for GrimoireExtensionMutator +impl Mutator for GrimoireExtensionMutator where - S: UsesInput + HasMetadata + HasRand + HasCorpus, + S: HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, state: &mut S, - input: &mut GeneralizedInput, + generalised_meta: &mut GeneralizedInputMetadata, _stage_idx: i32, ) -> Result { - if input.generalized().is_none() { - return Ok(MutationResult::Skipped); - } - extend_with_random_generalized( state, - input.generalized_mut().as_mut().unwrap(), + generalised_meta.generalized_mut(), &mut self.gap_indices, )?; - input.grimoire_mutated = true; Ok(MutationResult::Mutated) } } @@ -176,29 +166,25 @@ pub struct GrimoireRecursiveReplacementMutator { gap_indices: Vec, } -impl Mutator for GrimoireRecursiveReplacementMutator +impl Mutator for GrimoireRecursiveReplacementMutator where - S: UsesInput + HasMetadata + HasRand + HasCorpus, + S: HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, state: &mut S, - input: &mut GeneralizedInput, + generalised_meta: &mut GeneralizedInputMetadata, _stage_idx: i32, ) -> Result { - if input.generalized().is_none() { - return Ok(MutationResult::Skipped); - } - let mut mutated = MutationResult::Skipped; let depth = *state.rand_mut().choose(&RECURSIVE_REPLACEMENT_DEPTH); for _ in 0..depth { - if input.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN { + if generalised_meta.generalized_len() >= MAX_RECURSIVE_REPLACEMENT_LEN { break; } - let gen = input.generalized_mut().as_mut().unwrap(); + let gen = generalised_meta.generalized_mut(); for (i, _) in gen .iter() @@ -207,6 +193,9 @@ where { self.gap_indices.push(i); } + if self.gap_indices.is_empty() { + break; + } let selected = *state.rand_mut().choose(&self.gap_indices); self.gap_indices.clear(); @@ -219,7 +208,6 @@ where self.scratch.clear(); mutated = MutationResult::Mutated; - input.grimoire_mutated = true; } Ok(mutated) @@ -247,30 +235,28 @@ impl GrimoireRecursiveReplacementMutator { #[derive(Debug, Default)] pub struct GrimoireStringReplacementMutator {} -impl Mutator for GrimoireStringReplacementMutator +impl Mutator for GrimoireStringReplacementMutator where - S: UsesInput + HasMetadata + HasRand, + S: HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, state: &mut S, - input: &mut GeneralizedInput, + generalised_meta: &mut GeneralizedInputMetadata, _stage_idx: i32, ) -> Result { - if input.generalized().is_none() { - return Ok(MutationResult::Skipped); - } - let tokens_len = { let meta = state.metadata().get::(); - if meta.is_none() { + if let Some(tokens) = meta { + if tokens.is_empty() { + return Ok(MutationResult::Skipped); + } + tokens.tokens().len() + } else { return Ok(MutationResult::Skipped); } - if meta.unwrap().tokens().is_empty() { - return Ok(MutationResult::Skipped); - } - meta.unwrap().tokens().len() }; + let token_find = state.rand_mut().below(tokens_len as u64) as usize; let mut token_replace = state.rand_mut().below(tokens_len as u64) as usize; if token_find == token_replace { @@ -286,7 +272,7 @@ where let mut mutated = MutationResult::Skipped; - let gen = input.generalized_mut().as_mut().unwrap(); + let gen = generalised_meta.generalized_mut(); rand_idx %= gen.len(); 'first: for item in &mut gen[..rand_idx] { @@ -330,7 +316,6 @@ where } } - input.grimoire_mutated = true; Ok(mutated) } } @@ -355,22 +340,17 @@ pub struct GrimoireRandomDeleteMutator { gap_indices: Vec, } -impl Mutator for GrimoireRandomDeleteMutator +impl Mutator for GrimoireRandomDeleteMutator where - S: UsesInput + HasMetadata + HasRand + HasCorpus, + S: HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, state: &mut S, - input: &mut GeneralizedInput, + generalised_meta: &mut GeneralizedInputMetadata, _stage_idx: i32, ) -> Result { - if input.generalized().is_none() { - return Ok(MutationResult::Skipped); - } - - input.grimoire_mutated = true; - let gen = input.generalized_mut().as_mut().unwrap(); + let gen = generalised_meta.generalized_mut(); for (i, _) in gen .iter() @@ -387,12 +367,14 @@ where self.gap_indices.clear(); - if min_idx == max_idx { - Ok(MutationResult::Skipped) + let result = if min_idx == max_idx { + MutationResult::Skipped } else { gen.drain(min_idx..max_idx); - Ok(MutationResult::Mutated) - } + MutationResult::Mutated + }; + + Ok(result) } } diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index 964c36641a..4143fb2ec1 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -25,7 +25,6 @@ pub use nautilus::*; use crate::{ bolts::tuples::{HasConstLen, Named}, corpus::CorpusId, - inputs::UsesInput, Error, }; @@ -45,15 +44,12 @@ pub enum MutationResult { /// A mutator takes input, and mutates it. /// Simple as that. -pub trait Mutator -where - S: UsesInput, -{ +pub trait Mutator { /// Mutate a given input fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result; @@ -69,15 +65,12 @@ where } /// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. -pub trait MutatorsTuple: HasConstLen -where - S: UsesInput, -{ +pub trait MutatorsTuple: HasConstLen { /// Runs the `mutate` function on all `Mutators` in this `Tuple`. fn mutate_all( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result; @@ -94,7 +87,7 @@ where &mut self, index: usize, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result; @@ -108,14 +101,11 @@ where ) -> Result<(), Error>; } -impl MutatorsTuple for () -where - S: UsesInput, -{ +impl MutatorsTuple for () { fn mutate_all( &mut self, _state: &mut S, - _input: &mut S::Input, + _input: &mut I, _stage_idx: i32, ) -> Result { Ok(MutationResult::Skipped) @@ -134,7 +124,7 @@ where &mut self, _index: usize, _state: &mut S, - _input: &mut S::Input, + _input: &mut I, _stage_idx: i32, ) -> Result { Ok(MutationResult::Skipped) @@ -151,16 +141,15 @@ where } } -impl MutatorsTuple for (Head, Tail) +impl MutatorsTuple for (Head, Tail) where - Head: Mutator + Named, - Tail: MutatorsTuple, - S: UsesInput, + Head: Mutator + Named, + Tail: MutatorsTuple, { fn mutate_all( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { let r = self.0.mutate(state, input, stage_idx)?; @@ -185,7 +174,7 @@ where &mut self, index: usize, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { if index == 0 { @@ -238,7 +227,7 @@ pub mod pybind { } } - impl Mutator for PyObjectMutator { + impl Mutator for PyObjectMutator { fn mutate( &mut self, state: &mut PythonStdState, @@ -337,7 +326,7 @@ pub mod pybind { } } - impl Mutator for PythonMutator { + impl Mutator for PythonMutator { fn mutate( &mut self, state: &mut PythonStdState, diff --git a/libafl/src/mutators/mopt_mutator.rs b/libafl/src/mutators/mopt_mutator.rs index 62d39bb5c4..06cea8fae8 100644 --- a/libafl/src/mutators/mopt_mutator.rs +++ b/libafl/src/mutators/mopt_mutator.rs @@ -359,21 +359,21 @@ pub enum MOptMode { /// This is the main struct of `MOpt`, an `AFL` mutator. /// See the original `MOpt` implementation in -pub struct StdMOptMutator +pub struct StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { mode: MOptMode, finds_before: usize, mutations: MT, max_stack_pow: u64, - phantom: PhantomData, + phantom: PhantomData<(I, S)>, } -impl Debug for StdMOptMutator +impl Debug for StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -381,21 +381,21 @@ where f, "StdMOptMutator with {} mutations for Input type {}", self.mutations.len(), - core::any::type_name::() + core::any::type_name::() ) } } -impl Mutator for StdMOptMutator +impl Mutator for StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { #[inline] fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { self.finds_before = state.corpus().count() + state.solutions().count(); @@ -521,9 +521,9 @@ where } } -impl StdMOptMutator +impl StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Create a new [`StdMOptMutator`]. @@ -548,7 +548,7 @@ where fn core_mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -578,7 +578,7 @@ where fn pilot_mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -613,9 +613,9 @@ where } } -impl ComposedByMutations for StdMOptMutator +impl ComposedByMutations for StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Get the mutations @@ -631,19 +631,19 @@ where } } -impl ScheduledMutator for StdMOptMutator +impl ScheduledMutator for StdMOptMutator where - MT: MutatorsTuple, + MT: MutatorsTuple, S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { + fn iterations(&self, state: &mut S, _: &I) -> u64 { 1 << (1 + state.rand_mut().below(self.max_stack_pow)) } /// Get the next mutation to apply #[inline] - fn schedule(&self, state: &mut S, _: &S::Input) -> usize { + fn schedule(&self, state: &mut S, _: &I) -> usize { state .metadata_mut() .get_mut::() @@ -655,7 +655,7 @@ where fn scheduled_mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { let mode = self.mode; diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 48ae5ce8f4..c46f1168bf 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -9,7 +9,7 @@ use core::{ use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, - inputs::{HasBytesVec, UsesInput}, + inputs::HasBytesVec, mutators::{MutationResult, Mutator}, random_corpus_id, state::{HasCorpus, HasMaxSize, HasRand}, @@ -101,15 +101,15 @@ pub const INTERESTING_32: [i32; 27] = [ #[derive(Default, Debug)] pub struct BitFlipMutator; -impl Mutator for BitFlipMutator +impl Mutator for BitFlipMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut ::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -141,15 +141,15 @@ impl BitFlipMutator { #[derive(Default, Debug)] pub struct ByteFlipMutator; -impl Mutator for ByteFlipMutator +impl Mutator for ByteFlipMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -179,15 +179,15 @@ impl ByteFlipMutator { #[derive(Default, Debug)] pub struct ByteIncMutator; -impl Mutator for ByteIncMutator +impl Mutator for ByteIncMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -218,15 +218,15 @@ impl ByteIncMutator { #[derive(Default, Debug)] pub struct ByteDecMutator; -impl Mutator for ByteDecMutator +impl Mutator for ByteDecMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -257,15 +257,15 @@ impl ByteDecMutator { #[derive(Default, Debug)] pub struct ByteNegMutator; -impl Mutator for ByteNegMutator +impl Mutator for ByteNegMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -296,15 +296,15 @@ impl ByteNegMutator { #[derive(Default, Debug)] pub struct ByteRandMutator; -impl Mutator for ByteRandMutator +impl Mutator for ByteRandMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -340,15 +340,15 @@ macro_rules! add_mutator_impl { pub struct $name; #[allow(trivial_numeric_casts)] - impl Mutator for $name + impl Mutator for $name where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().len() < size_of::<$size>() { @@ -406,16 +406,16 @@ macro_rules! interesting_mutator_impl { #[derive(Default, Debug)] pub struct $name; - impl Mutator for $name + impl Mutator for $name where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { #[allow(clippy::cast_sign_loss)] fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { if input.bytes().len() < size_of::<$size>() { @@ -459,15 +459,15 @@ interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32); #[derive(Default, Debug)] pub struct BytesDeleteMutator; -impl Mutator for BytesDeleteMutator +impl Mutator for BytesDeleteMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -501,15 +501,15 @@ impl BytesDeleteMutator { #[derive(Default, Debug)] pub struct BytesExpandMutator; -impl Mutator for BytesExpandMutator +impl Mutator for BytesExpandMutator where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, + S: HasRand + HasMaxSize, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -550,15 +550,15 @@ impl BytesExpandMutator { #[derive(Default, Debug)] pub struct BytesInsertMutator; -impl Mutator for BytesInsertMutator +impl Mutator for BytesInsertMutator where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, + S: HasRand + HasMaxSize, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -605,15 +605,15 @@ impl BytesInsertMutator { #[derive(Default, Debug)] pub struct BytesRandInsertMutator; -impl Mutator for BytesRandInsertMutator +impl Mutator for BytesRandInsertMutator where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, + S: HasRand + HasMaxSize, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -657,15 +657,15 @@ impl BytesRandInsertMutator { #[derive(Default, Debug)] pub struct BytesSetMutator; -impl Mutator for BytesSetMutator +impl Mutator for BytesSetMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -701,15 +701,15 @@ impl BytesSetMutator { #[derive(Default, Debug)] pub struct BytesRandSetMutator; -impl Mutator for BytesRandSetMutator +impl Mutator for BytesRandSetMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -745,15 +745,15 @@ impl BytesRandSetMutator { #[derive(Default, Debug)] pub struct BytesCopyMutator; -impl Mutator for BytesCopyMutator +impl Mutator for BytesCopyMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -791,15 +791,15 @@ pub struct BytesInsertCopyMutator { tmp_buf: Vec, } -impl Mutator for BytesInsertCopyMutator +impl Mutator for BytesInsertCopyMutator where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, + S: HasRand + HasMaxSize, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -853,15 +853,15 @@ impl BytesInsertCopyMutator { #[derive(Debug, Default)] pub struct BytesSwapMutator; -impl Mutator for BytesSwapMutator +impl Mutator for BytesSwapMutator where - S: UsesInput + HasRand, - S::Input: HasBytesVec, + S: HasRand, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -899,7 +899,7 @@ impl BytesSwapMutator { #[derive(Debug, Default)] pub struct CrossoverInsertMutator; -impl Mutator for CrossoverInsertMutator +impl Mutator for CrossoverInsertMutator where S: HasCorpus + HasRand + HasMaxSize, S::Input: HasBytesVec, @@ -974,7 +974,7 @@ impl CrossoverInsertMutator { #[derive(Debug, Default)] pub struct CrossoverReplaceMutator; -impl Mutator for CrossoverReplaceMutator +impl Mutator for CrossoverReplaceMutator where S: HasCorpus + HasRand, S::Input: HasBytesVec, @@ -1056,7 +1056,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { #[derive(Debug, Default)] pub struct SpliceMutator; -impl Mutator for SpliceMutator +impl Mutator for SpliceMutator where S: HasCorpus + HasRand, S::Input: HasBytesVec, @@ -1178,10 +1178,10 @@ mod tests { state::{HasMetadata, StdState}, }; - fn test_mutations() -> impl MutatorsTuple + fn test_mutations() -> impl MutatorsTuple where - S: HasRand + HasCorpus + HasMetadata + HasMaxSize, - S::Input: HasBytesVec, + S: HasRand + HasMetadata + HasMaxSize, + I: HasBytesVec, { tuple_list!( BitFlipMutator::new(), diff --git a/libafl/src/mutators/nautilus.rs b/libafl/src/mutators/nautilus.rs index 9f866dc140..687fd5dccd 100644 --- a/libafl/src/mutators/nautilus.rs +++ b/libafl/src/mutators/nautilus.rs @@ -14,7 +14,6 @@ use crate::{ generators::nautilus::NautilusContext, inputs::nautilus::NautilusInput, mutators::{MutationResult, Mutator}, - prelude::UsesInput, state::{HasCorpus, HasMetadata}, Error, }; @@ -31,10 +30,7 @@ impl Debug for NautilusRandomMutator<'_> { } } -impl Mutator for NautilusRandomMutator<'_> -where - S: UsesInput, -{ +impl Mutator for NautilusRandomMutator<'_> { fn mutate( &mut self, _state: &mut S, @@ -95,10 +91,7 @@ impl Debug for NautilusRecursionMutator<'_> { } } -impl Mutator for NautilusRecursionMutator<'_> -where - S: UsesInput, -{ +impl Mutator for NautilusRecursionMutator<'_> { fn mutate( &mut self, _state: &mut S, @@ -161,9 +154,9 @@ impl Debug for NautilusSpliceMutator<'_> { } } -impl Mutator for NautilusSpliceMutator<'_> +impl Mutator for NautilusSpliceMutator<'_> where - S: HasCorpus + HasMetadata + UsesInput, + S: HasCorpus + HasMetadata, { fn mutate( &mut self, diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index edc483f505..7e9ca0b67b 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -16,9 +16,8 @@ use crate::{ AsMutSlice, AsSlice, }, corpus::{Corpus, CorpusId}, - inputs::UsesInput, mutators::{MutationResult, Mutator, MutatorsTuple}, - state::{HasCorpus, HasMetadata, HasRand, State}, + state::{HasCorpus, HasMetadata, HasRand}, Error, }; @@ -55,10 +54,9 @@ impl LogMutationMetadata { } /// A [`Mutator`] that composes multiple mutations into one. -pub trait ComposedByMutations +pub trait ComposedByMutations where - MT: MutatorsTuple, - S: UsesInput, + MT: MutatorsTuple, { /// Get the mutations fn mutations(&self) -> &MT; @@ -68,23 +66,22 @@ where } /// A [`Mutator`] scheduling multiple [`Mutator`]s for an input. -pub trait ScheduledMutator: ComposedByMutations + Mutator +pub trait ScheduledMutator: ComposedByMutations + Mutator where - MT: MutatorsTuple, - S: UsesInput, + MT: MutatorsTuple, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, input: &S::Input) -> u64; + fn iterations(&self, state: &mut S, input: &I) -> u64; /// Get the next mutation to apply - fn schedule(&self, state: &mut S, input: &S::Input) -> usize; + fn schedule(&self, state: &mut S, input: &I) -> usize; /// New default implementation for mutate. /// Implementations must forward mutate() to this method fn scheduled_mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -103,51 +100,51 @@ where } /// A [`Mutator`] that schedules one of the embedded mutations on each call. -pub struct StdScheduledMutator +pub struct StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { mutations: MT, max_stack_pow: u64, - phantom: PhantomData, + phantom: PhantomData<(I, S)>, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "StdScheduledMutator with {} mutations for Input type {}", self.mutations.len(), - core::any::type_name::() + core::any::type_name::() ) } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { #[inline] fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { self.scheduled_mutate(state, input, stage_idx) } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { /// Get the mutations #[inline] @@ -162,27 +159,27 @@ where } } -impl ScheduledMutator for StdScheduledMutator +impl ScheduledMutator for StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { + fn iterations(&self, state: &mut S, _: &I) -> u64 { 1 << (1 + state.rand_mut().below(self.max_stack_pow)) } /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &S::Input) -> usize { + fn schedule(&self, state: &mut S, _: &I) -> usize { debug_assert!(!self.mutations().is_empty()); state.rand_mut().below(self.mutations().len() as u64) as usize } } -impl StdScheduledMutator +impl StdScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { /// Create a new [`StdScheduledMutator`] instance specifying mutations pub fn new(mutations: MT) -> Self { @@ -275,43 +272,43 @@ pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) { } /// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`]. -pub struct LoggerScheduledMutator +pub struct LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: UsesInput + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { scheduled: SM, mutation_log: Vec, - phantom: PhantomData<(MT, S)>, + phantom: PhantomData<(I, MT, S)>, } -impl Debug for LoggerScheduledMutator +impl Debug for LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: UsesInput + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "LoggerScheduledMutator with {} mutations for Input type {}", self.scheduled.mutations().len(), - core::any::type_name::<::Input>() + core::any::type_name::() ) } } -impl Mutator for LoggerScheduledMutator +impl Mutator for LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { fn mutate( &mut self, state: &mut S, - input: &mut ::Input, + input: &mut I, stage_idx: i32, ) -> Result { self.scheduled_mutate(state, input, stage_idx) @@ -339,11 +336,11 @@ where } } -impl ComposedByMutations for LoggerScheduledMutator +impl ComposedByMutations for LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { #[inline] fn mutations(&self) -> &MT { @@ -356,19 +353,19 @@ where } } -impl ScheduledMutator for LoggerScheduledMutator +impl ScheduledMutator for LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &::Input) -> 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, state: &mut S, _: &::Input) -> usize { + fn schedule(&self, state: &mut S, _: &I) -> usize { debug_assert!(!self.scheduled.mutations().is_empty()); state .rand_mut() @@ -378,7 +375,7 @@ where fn scheduled_mutate( &mut self, state: &mut S, - input: &mut ::Input, + input: &mut I, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -398,11 +395,11 @@ where } } -impl LoggerScheduledMutator +impl LoggerScheduledMutator where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: HasRand + HasCorpus, + SM: ScheduledMutator, { /// Create a new [`StdScheduledMutator`] instance without mutations and corpus pub fn new(scheduled: SM) -> Self { @@ -528,14 +525,16 @@ pub mod pybind { use pyo3::prelude::*; use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator}; - use crate::{mutators::pybind::PythonMutator, state::pybind::PythonStdState}; + use crate::{ + inputs::BytesInput, mutators::pybind::PythonMutator, state::pybind::PythonStdState, + }; #[pyclass(unsendable, name = "StdHavocMutator")] #[derive(Debug)] /// Python class for StdHavocMutator pub struct PythonStdHavocMutator { /// Rust wrapped StdHavocMutator object - pub inner: StdScheduledMutator, + pub inner: StdScheduledMutator, } #[pymethods] diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index a875c547b1..9a144d4ef3 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -291,15 +291,15 @@ impl<'it> IntoIterator for &'it Tokens { #[derive(Debug, Default)] pub struct TokenInsert; -impl Mutator for TokenInsert +impl Mutator for TokenInsert where - S: UsesInput + HasMetadata + HasRand + HasMaxSize, - S::Input: HasBytesVec, + S: HasMetadata + HasRand + HasMaxSize, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -357,15 +357,15 @@ impl TokenInsert { #[derive(Debug, Default)] pub struct TokenReplace; -impl Mutator for TokenReplace +impl Mutator for TokenReplace where S: UsesInput + HasMetadata + HasRand + HasMaxSize, - S::Input: HasBytesVec, + I: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -419,16 +419,16 @@ impl TokenReplace { #[derive(Debug, Default)] pub struct I2SRandReplace; -impl Mutator for I2SRandReplace +impl Mutator for I2SRandReplace where S: UsesInput + HasMetadata + HasRand + HasMaxSize, - S::Input: HasBytesVec, + I: HasBytesVec, { #[allow(clippy::too_many_lines)] fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); diff --git a/libafl/src/mutators/tuneable.rs b/libafl/src/mutators/tuneable.rs index d678220fdb..efcfabe687 100644 --- a/libafl/src/mutators/tuneable.rs +++ b/libafl/src/mutators/tuneable.rs @@ -15,7 +15,7 @@ use crate::{ bolts::rands::Rand, impl_serdeany, mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator}, - state::{HasMetadata, HasRand, State}, + state::{HasMetadata, HasRand}, Error, }; @@ -54,51 +54,51 @@ impl_serdeany!(TuneableScheduledMutatorMetadata); /// A [`Mutator`] that schedules one of the embedded mutations on each call. /// The index of the next mutation can be set. -pub struct TuneableScheduledMutator +pub struct TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { mutations: MT, max_stack_pow: u64, - phantom: PhantomData, + phantom: PhantomData<(I, S)>, } -impl Debug for TuneableScheduledMutator +impl Debug for TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "TuneableScheduledMutator with {} mutations for Input type {}", self.mutations.len(), - core::any::type_name::() + core::any::type_name::() ) } } -impl Mutator for TuneableScheduledMutator +impl Mutator for TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand + HasMetadata, + MT: MutatorsTuple, + S: HasRand + HasMetadata, { #[inline] fn mutate( &mut self, state: &mut S, - input: &mut S::Input, + input: &mut I, stage_idx: i32, ) -> Result { self.scheduled_mutate(state, input, stage_idx) } } -impl ComposedByMutations for TuneableScheduledMutator +impl ComposedByMutations for TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand, + MT: MutatorsTuple, + S: HasRand, { /// Get the mutations #[inline] @@ -113,13 +113,13 @@ where } } -impl ScheduledMutator for TuneableScheduledMutator +impl ScheduledMutator for TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand + HasMetadata, + MT: MutatorsTuple, + S: HasRand + HasMetadata, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { + fn iterations(&self, state: &mut S, _: &I) -> u64 { if let Some(iters) = Self::get_iters(state) { iters } else { @@ -129,7 +129,7 @@ where } /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &S::Input) -> usize { + fn schedule(&self, state: &mut S, _: &I) -> usize { debug_assert!(!self.mutations().is_empty()); // Assumption: we can not reach this code path without previously adding this metadatum. let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap(); @@ -152,10 +152,10 @@ where } } -impl TuneableScheduledMutator +impl TuneableScheduledMutator where - MT: MutatorsTuple, - S: State + HasRand + HasMetadata, + MT: MutatorsTuple, + S: HasRand + HasMetadata, { /// Create a new [`TuneableScheduledMutator`] instance specifying mutations pub fn new(state: &mut S, mutations: MT) -> Self { @@ -222,7 +222,7 @@ mod test { #[test] fn test_tuning() { - let mut state = NopState::new(); + let mut state: NopState = NopState::new(); let mutators = tuple_list!( BitFlipMutator::new(), ByteDecMutator::new(), diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index 0e94d8338e..d525c0137b 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -16,7 +16,7 @@ use crate::{ corpus::{Corpus, CorpusId}, executors::{Executor, HasObservers}, feedbacks::map::MapNoveltiesMetadata, - inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput}, + inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput}, mark_feature_time, observers::{MapObserver, ObserversTuple}, stages::Stage, @@ -69,7 +69,7 @@ pub struct GeneralizationStage { impl UsesState for GeneralizationStage where EM: UsesState, - EM::State: UsesInput, + EM::State: UsesInput, { type State = EM::State; } @@ -79,7 +79,7 @@ where O: MapObserver, E: Executor + HasObservers, E::Observers: ObserversTuple, - E::State: UsesInput + E::State: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata @@ -110,9 +110,8 @@ where state.corpus().get(corpus_idx)?.borrow_mut().load_input()?; mark_feature_time!(state, PerfFeature::GetInputFromCorpus); let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); - let input = entry.input_mut().as_mut().unwrap(); - if input.generalized().is_some() { + if entry.metadata().contains::() { drop(entry); state .metadata_mut() @@ -123,6 +122,8 @@ where return Ok(()); } + let input = entry.input_mut().as_mut().unwrap(); + let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect(); let original = input.clone(); let meta = entry.metadata().get::().ok_or_else(|| { @@ -324,23 +325,13 @@ where if payload.len() <= MAX_GENERALIZED_LEN { // Save the modified input in the corpus { - let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); - entry.load_input()?; - entry - .input_mut() - .as_mut() - .unwrap() - .generalized_from_options(&payload); - entry.store_input()?; + let meta = GeneralizedInputMetadata::generalized_from_options(&payload); - debug_assert!( - entry.load_input()?.generalized().unwrap().first() - == Some(&GeneralizedItem::Gap) - ); - debug_assert!( - entry.load_input()?.generalized().unwrap().last() - == Some(&GeneralizedItem::Gap) - ); + debug_assert!(meta.generalized().first() == Some(&GeneralizedItem::Gap)); + debug_assert!(meta.generalized().last() == Some(&GeneralizedItem::Gap)); + + let mut entry = state.corpus().get(corpus_idx)?.borrow_mut(); + entry.metadata_mut().insert(meta); } state @@ -360,7 +351,7 @@ where EM: UsesState, O: MapObserver, OT: ObserversTuple, - EM::State: UsesInput + EM::State: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata @@ -391,7 +382,7 @@ where state: &mut EM::State, manager: &mut EM, novelties: &[usize], - input: &GeneralizedInput, + input: &BytesInput, ) -> Result where E: Executor + HasObservers, @@ -449,7 +440,7 @@ where if end > payload.len() { end = payload.len(); } - let mut candidate = GeneralizedInput::new(vec![]); + let mut candidate = BytesInput::new(vec![]); candidate .bytes_mut() .extend(payload[..start].iter().flatten()); @@ -502,7 +493,7 @@ where while end > start { if payload[end] == Some(closing_char) { endings += 1; - let mut candidate = GeneralizedInput::new(vec![]); + let mut candidate = BytesInput::new(vec![]); candidate .bytes_mut() .extend(payload[..start].iter().flatten()); diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 016d3626cb..3629ef4b58 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -7,8 +7,9 @@ use core::marker::PhantomData; use crate::monitors::PerfFeature; use crate::{ bolts::rands::Rand, - corpus::{Corpus, CorpusId}, + corpus::{Corpus, CorpusId, Testcase}, fuzzer::Evaluator, + inputs::Input, mark_feature_time, mutators::Mutator, stages::Stage, @@ -19,16 +20,79 @@ use crate::{ // TODO multi mutators stage +/// Action performed after the un-transformed input is executed (e.g., updating metadata) +#[allow(unused_variables)] +pub trait MutatedTransformPost: Sized { + /// Perform any post-execution steps necessary for the transformed input (e.g., updating metadata) + #[inline] + fn post_exec( + self, + state: &mut S, + stage_idx: i32, + corpus_idx: Option, + ) -> Result<(), Error> { + Ok(()) + } +} + +impl MutatedTransformPost for () {} + +/// A type which may both be transformed from and into a given input type, used to perform +/// mutations over inputs which are not necessarily performable on the underlying type +/// +/// This trait is implemented such that all testcases inherently transform to their inputs, should +/// the input be cloneable. +pub trait MutatedTransform: Sized +where + I: Input, +{ + /// Type indicating actions to be taken after the post-transformation input is executed + type Post: MutatedTransformPost; + + /// Transform the provided testcase into this type + fn try_transform_from( + base: &Testcase, + state: &S, + corpus_idx: CorpusId, + ) -> Result; + + /// Transform this instance back into the original input type + fn try_transform_into(self, state: &S) -> Result<(I, Self::Post), Error>; +} + +// reflexive definition +impl MutatedTransform for I +where + I: Input + Clone, +{ + type Post = (); + + #[inline] + fn try_transform_from( + base: &Testcase, + _state: &S, + _corpus_idx: CorpusId, + ) -> Result { + Ok(base.input().as_ref().unwrap().clone()) + } + + #[inline] + fn try_transform_into(self, _state: &S) -> Result<(I, Self::Post), Error> { + Ok((self, ())) + } +} + /// 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 E: UsesState, - M: Mutator, + M: Mutator, EM: UsesState, Z: Evaluator, Self::State: HasClientPerfMonitor + HasCorpus, + I: MutatedTransform + Clone, { /// The mutator registered for this stage fn mutator(&self) -> &M; @@ -51,25 +115,26 @@ where ) -> Result<(), Error> { let num = self.iterations(state, corpus_idx)?; + start_timer!(state); + let testcase = state.corpus().get(corpus_idx)?.borrow(); + let input = I::try_transform_from(&testcase, state, corpus_idx)?; + drop(testcase); + mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + for i in 0..num { - start_timer!(state); - let mut input = state - .corpus() - .get(corpus_idx)? - .borrow_mut() - .load_input()? - .clone(); - mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + let mut input = input.clone(); start_timer!(state); self.mutator_mut().mutate(state, &mut input, i as i32)?; mark_feature_time!(state, PerfFeature::Mutate); // Time is measured directly the `evaluate_input` function - let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; + let (untransformed, post) = input.try_transform_into(state)?; + let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; start_timer!(state); self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; + post.post_exec(state, i as i32, corpus_idx)?; mark_feature_time!(state, PerfFeature::MutatePostExec); } Ok(()) @@ -82,19 +147,20 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; /// The default mutational stage #[derive(Clone, Debug)] -pub struct StdMutationalStage { +pub struct StdMutationalStage { mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, I, Z)>, } -impl MutationalStage for StdMutationalStage +impl MutationalStage for StdMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand, + I: MutatedTransform + Clone, { /// The mutator, added to this stage #[inline] @@ -114,24 +180,25 @@ where } } -impl UsesState for StdMutationalStage +impl UsesState for StdMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand, { type State = Z::State; } -impl Stage for StdMutationalStage +impl Stage for StdMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand, + I: MutatedTransform + Clone, { #[inline] #[allow(clippy::let_and_return)] @@ -152,16 +219,30 @@ where } } -impl StdMutationalStage +impl StdMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand, { /// Creates a new default mutational stage pub fn new(mutator: M) -> Self { + Self::transforming(mutator) + } +} + +impl StdMutationalStage +where + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand, +{ + /// Creates a new transforming mutational stage + pub fn transforming(mutator: M) -> Self { Self { mutator, phantom: PhantomData, @@ -179,6 +260,7 @@ pub mod pybind { events::pybind::PythonEventManager, executors::pybind::PythonExecutor, fuzzer::pybind::PythonStdFuzzer, + inputs::BytesInput, mutators::pybind::PythonMutator, stages::{pybind::PythonStage, StdMutationalStage}, }; @@ -188,8 +270,13 @@ pub mod pybind { /// Python class for StdMutationalStage pub struct PythonStdMutationalStage { /// Rust wrapped StdMutationalStage object - pub inner: - StdMutationalStage, + pub inner: StdMutationalStage< + PythonExecutor, + PythonEventManager, + BytesInput, + PythonMutator, + PythonStdFuzzer, + >, } #[pymethods] diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index 70719cfa31..056f5884d7 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -13,36 +13,41 @@ use crate::{ schedulers::{ powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore, }, - stages::{MutationalStage, Stage}, + stages::{ + mutational::{MutatedTransform, MutatedTransformPost}, + MutationalStage, Stage, + }, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct PowerMutationalStage { +pub struct PowerMutationalStage { map_observer_name: String, mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, F, EM, O, Z)>, + phantom: PhantomData<(E, F, EM, I, O, Z)>, } -impl UsesState for PowerMutationalStage +impl UsesState for PowerMutationalStage where E: UsesState, { type State = E::State; } -impl MutationalStage for PowerMutationalStage +impl MutationalStage + for PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, - M: Mutator, + M: Mutator, O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, + I: MutatedTransform + Clone, { /// The mutator, added to this stage #[inline] @@ -77,17 +82,17 @@ where ) -> Result<(), Error> { let num = self.iterations(state, corpus_idx)?; + let testcase = state.corpus().get(corpus_idx)?.borrow(); + let input = I::try_transform_from(&testcase, state, corpus_idx)?; + drop(testcase); + for i in 0..num { - let mut input = state - .corpus() - .get(corpus_idx)? - .borrow_mut() - .load_input()? - .clone(); + let mut input = input.clone(); self.mutator_mut().mutate(state, &mut input, i as i32)?; - let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; + let (untransformed, post) = input.try_transform_into(state)?; + let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, untransformed)?; let observer = executor .observers() @@ -119,21 +124,23 @@ where } self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; + post.post_exec(state, i as i32, corpus_idx)?; } Ok(()) } } -impl Stage for PowerMutationalStage +impl Stage for PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, - M: Mutator, + M: Mutator, O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, + I: MutatedTransform + Clone, { #[inline] #[allow(clippy::let_and_return)] @@ -150,18 +157,34 @@ where } } -impl PowerMutationalStage +impl PowerMutationalStage where E: Executor + HasObservers, EM: UsesState, F: TestcaseScore, - M: Mutator, + M: Mutator, O: MapObserver, E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, Z: Evaluator, { /// Creates a new [`PowerMutationalStage`] pub fn new(mutator: M, map_observer_name: &O) -> Self { + Self::transforming(mutator, map_observer_name) + } +} + +impl PowerMutationalStage +where + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, + M: Mutator, + O: MapObserver, + E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, + Z: Evaluator, +{ + /// Creates a new transforming [`PowerMutationalStage`] + pub fn transforming(mutator: M, map_observer_name: &O) -> Self { Self { map_observer_name: map_observer_name.name().to_string(), mutator, @@ -171,5 +194,5 @@ where } /// The standard powerscheduling stage -pub type StdPowerMutationalStage = - PowerMutationalStage::State>, EM, M, O, Z>; +pub type StdPowerMutationalStage = + PowerMutationalStage::State>, EM, I, M, O, Z>; diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index a0b6d8f7d9..b437a6f264 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -41,7 +41,7 @@ pub struct StdMutationalPushStage where CS: Scheduler, EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasRand + Clone + Debug, Z: ExecutionProcessor @@ -63,7 +63,7 @@ impl StdMutationalPushStage where CS: Scheduler, EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, Z: ExecutionProcessor @@ -86,7 +86,7 @@ impl PushStage for StdMutationalPushStage + EventRestarter + HasEventManagerId + ProgressReporter, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, @@ -199,7 +199,7 @@ impl Iterator for StdMutationalPushStage where CS: Scheduler, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, @@ -218,7 +218,7 @@ impl StdMutationalPushStage where CS: Scheduler, EM: EventFirer + EventRestarter + HasEventManagerId, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, Z: ExecutionProcessor diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index e3faa7826e..eb1218ee8c 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -41,7 +41,7 @@ where EM: EventFirer, F1: Feedback, F2: Feedback, - M: Mutator, + M: Mutator, OT: ObserversTuple, Z: ExecutionProcessor + ExecutesInput @@ -177,7 +177,7 @@ impl UsesState for StdTMinMutationalStage where CS: Scheduler, - M: Mutator, + M: Mutator, Z: ExecutionProcessor, { type State = CS::State; @@ -194,7 +194,7 @@ where F1: Feedback, F2: Feedback, FF: FeedbackFactory, - M: Mutator, + M: Mutator, OT: ObserversTuple, Z: ExecutionProcessor + ExecutesInput @@ -241,7 +241,7 @@ where F2: Feedback, FF: FeedbackFactory, ::Input: HasLen + Hash, - M: Mutator, + M: Mutator, OT: ObserversTuple, CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, Z: ExecutionProcessor @@ -270,7 +270,7 @@ where impl StdTMinMutationalStage where CS: Scheduler, - M: Mutator, + M: Mutator, Z: ExecutionProcessor, { /// Creates a new minimising mutational stage that will minimize provided corpus entries diff --git a/libafl/src/stages/tuneable.rs b/libafl/src/stages/tuneable.rs index efdce30084..1e955750c5 100644 --- a/libafl/src/stages/tuneable.rs +++ b/libafl/src/stages/tuneable.rs @@ -9,7 +9,10 @@ use crate::{ corpus::CorpusId, impl_serdeany, mutators::Mutator, - stages::{mutational::DEFAULT_MUTATIONAL_MAX_ITERATIONS, MutationalStage, Stage}, + stages::{ + mutational::{MutatedTransform, DEFAULT_MUTATIONAL_MAX_ITERATIONS}, + MutationalStage, Stage, + }, state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, Error, Evaluator, }; @@ -52,18 +55,19 @@ pub fn reset(state: &mut S) -> Result<(), Error> { /// A [`crate::stages::MutationalStage`] where the mutator iteration can be tuned at runtime #[derive(Clone, Debug)] -pub struct TuneableMutationalStage { +pub struct TuneableMutationalStage { mutator: M, - phantom: PhantomData<(E, EM, Z)>, + phantom: PhantomData<(E, EM, I, Z)>, } -impl MutationalStage for TuneableMutationalStage +impl MutationalStage for TuneableMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, + I: MutatedTransform + Clone, { /// The mutator, added to this stage #[inline] @@ -89,24 +93,26 @@ where } } -impl UsesState for TuneableMutationalStage +impl UsesState for TuneableMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand, + I: MutatedTransform + Clone, { type State = Z::State; } -impl Stage for TuneableMutationalStage +impl Stage for TuneableMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, + I: MutatedTransform + Clone, { #[inline] #[allow(clippy::let_and_return)] @@ -127,17 +133,32 @@ where } } -impl TuneableMutationalStage +impl TuneableMutationalStage where E: UsesState, EM: UsesState, - M: Mutator, + M: Mutator, Z: Evaluator, Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, { /// Creates a new default mutational stage #[must_use] pub fn new(state: &mut Z::State, mutator: M) -> Self { + Self::transforming(state, mutator) + } +} + +impl TuneableMutationalStage +where + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, +{ + /// Creates a new tranforming mutational stage + #[must_use] + pub fn transforming(state: &mut Z::State, mutator: M) -> Self { if !state.has_metadata::() { state.add_metadata(TuneableMutationalStageMetadata::default()); }