From 798aa2ceb9ce32464a8520647bcb731f2c0e5c89 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Fri, 2 Jun 2023 10:00:13 +0200 Subject: [PATCH] remove dead code --- fuzzers/FRET/benchmark/Snakefile | 15 +- fuzzers/FRET/src/fuzzer.rs | 5 +- fuzzers/FRET/src/mutational.rs | 153 +-- fuzzers/FRET/src/systemstate/mod.rs | 2 - fuzzers/FRET/src/systemstate/mutation/mod.rs | 185 --- .../src/systemstate/mutation/mutations.rs | 1189 ----------------- .../src/systemstate/mutation/scheduled.rs | 421 ------ fuzzers/FRET/src/systemstate/mutators.rs | 253 ---- 8 files changed, 10 insertions(+), 2213 deletions(-) delete mode 100644 fuzzers/FRET/src/systemstate/mutation/mod.rs delete mode 100644 fuzzers/FRET/src/systemstate/mutation/mutations.rs delete mode 100644 fuzzers/FRET/src/systemstate/mutation/scheduled.rs delete mode 100644 fuzzers/FRET/src/systemstate/mutators.rs diff --git a/fuzzers/FRET/benchmark/Snakefile b/fuzzers/FRET/benchmark/Snakefile index b886ff4770..030f5f7818 100644 --- a/fuzzers/FRET/benchmark/Snakefile +++ b/fuzzers/FRET/benchmark/Snakefile @@ -235,15 +235,6 @@ rule trace2gantt: shell: "Rscript --vanilla $(pwd)/../../../../state2gantt/gantt.R {input}" -rule all_bins: - input: - "bins/target_random", - "bins/target_feedlongest", - "bins/target_feedaflnolongest", - "bins/target_afl", - "bins/target_state", - "bins/target_graph" - rule all_main: input: expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['random','afl','feedgeneration10','state'], target=['waters','watersv2'],num=range(0,3)) @@ -283,4 +274,8 @@ rule clusterfuzz: expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1','feedgeneration10','feedgeneration100'], target=['waters_int','watersv2'],num=MY_RANGE_B), expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['feedgeneration1_int','feedgeneration10_int','feedgeneration100_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_B), expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl','frafl','feedlongest'], target=['waters','watersv2'],num=MY_RANGE_B), - expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl_int','frafl_int','feedlongest_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_B), \ No newline at end of file + expand("timedump/{fuzzer}/{target}.{num}", fuzzer=['afl_int','frafl_int','feedlongest_int'], target=['waters_int','watersv2_int'],num=MY_RANGE_B), + +rule all_bins: + input: + expand("bins/target_{target}{flag}",target=['random','afl','frafl','state','feedgeneration100'],flag=['','_int']) \ No newline at end of file diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 8f36caf8ed..04ebd07eeb 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -37,10 +37,9 @@ use rand::{SeedableRng, StdRng, Rng}; use crate::{ clock::{QemuClockObserver, ClockTimeFeedback, QemuClockIncreaseFeedback, IcHist, FUZZ_START_TIMESTAMP}, qemustate::QemuStateRestoreHelper, - systemstate::{mutators::{MINIMUM_INTER_ARRIVAL_TIME}, helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{SysMapFeedback, SysGraphFeedbackState, GraphMaximizerCorpusScheduler}, schedulers::{LongestTraceScheduler, GenerationScheduler}}, worst::{TimeMaximizerCorpusScheduler, ExecTimeIncFeedback, TimeStateMaximizerCorpusScheduler, AlwaysTrueFeedback}, + systemstate::{helpers::QemuSystemStateHelper, observers::QemuSystemStateObserver, feedbacks::{DumpSystraceFeedback, NovelSystemStateFeedback}, graph::{SysMapFeedback, SysGraphFeedbackState, GraphMaximizerCorpusScheduler}, schedulers::{LongestTraceScheduler, GenerationScheduler}}, worst::{TimeMaximizerCorpusScheduler, ExecTimeIncFeedback, TimeStateMaximizerCorpusScheduler, AlwaysTrueFeedback}, mutational::MyStateStage, - // systemstate::mutation::scheduled::{havoc_mutations, StdScheduledMutator}, - // mutational::StdMutationalStage + mutational::{MINIMUM_INTER_ARRIVAL_TIME}, }; use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/fuzzers/FRET/src/mutational.rs b/fuzzers/FRET/src/mutational.rs index cf81fc2405..5262147620 100644 --- a/fuzzers/FRET/src/mutational.rs +++ b/fuzzers/FRET/src/mutational.rs @@ -12,157 +12,11 @@ use libafl::{ stages::{Stage}, start_timer, state::{HasClientPerfMonitor, HasCorpus, HasRand, UsesState, HasMetadata}, - Error, prelude::{HasBytesVec, UsesInput, new_hash_feedback, StdRand, RandomSeed, MutationResult}, + Error, prelude::{HasBytesVec, UsesInput, new_hash_feedback, StdRand, RandomSeed, MutationResult, Mutator}, }; -use crate::{systemstate::{mutation::Mutator, mutators::{InterruptShifterMutator, MINIMUM_INTER_ARRIVAL_TIME}, FreeRTOSSystemStateMetadata, RefinedFreeRTOSSystemState}, fuzzer::DO_NUM_INTERRUPT, clock::IcHist}; - -// TODO multi mutators stage - -/// 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 -where - E: UsesState, - M: Mutator, - EM: UsesState, - Z: Evaluator, - Self::State: HasClientPerfMonitor + HasCorpus, -{ - /// The mutator registered for this stage - fn mutator(&self) -> &M; - - /// The mutator registered for this stage (mutable) - fn mutator_mut(&mut self) -> &mut M; - - /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result; - - /// Runs this (mutational) stage for the given testcase - #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... - fn perform_mutational( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Z::State, - manager: &mut EM, - corpus_idx: usize, - ) -> Result<(), Error> { - let num = self.iterations(state, corpus_idx)?; - - for i in 0..num { - start_timer!(state); - let mut input = state - .corpus() - .get(corpus_idx)? - .borrow_mut() - .clone(); - mark_feature_time!(state, PerfFeature::GetInputFromCorpus); - - 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.load_input()?.clone())?; - - start_timer!(state); - self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; - mark_feature_time!(state, PerfFeature::MutatePostExec); - } - Ok(()) - } -} - -/// Default value, how many iterations each stage gets, as an upper bound. -/// It may randomly continue earlier. -pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; - -/// The default mutational stage -#[derive(Clone, Debug)] -pub struct StdMutationalStage { - mutator: M, - #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, Z)>, -} - -impl MutationalStage for StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasClientPerfMonitor + HasCorpus + HasRand, -{ - /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { - &self.mutator - } - - /// The list of mutators, added to this stage (as mutable ref) - #[inline] - fn mutator_mut(&mut self) -> &mut M { - &mut self.mutator - } - - /// Gets the number of iterations as a random number - fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result { - Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS)) - } -} - -impl UsesState for StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasClientPerfMonitor + HasCorpus + HasRand, -{ - type State = Z::State; -} - -impl Stage for StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasClientPerfMonitor + HasCorpus + HasRand, -{ - #[inline] - #[allow(clippy::let_and_return)] - fn perform( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut Z::State, - manager: &mut EM, - corpus_idx: usize, - ) -> Result<(), Error> { - let ret = self.perform_mutational(fuzzer, executor, state, manager, corpus_idx); - ret - } -} - -impl StdMutationalStage -where - E: UsesState, - EM: UsesState, - M: Mutator, - Z: Evaluator, - Z::State: HasClientPerfMonitor + HasCorpus + HasRand, -{ - /// Creates a new default mutational stage - pub fn new(mutator: M) -> Self { - Self { - mutator, - phantom: PhantomData, - } - } -} +use crate::{systemstate::{FreeRTOSSystemStateMetadata, RefinedFreeRTOSSystemState}, fuzzer::DO_NUM_INTERRUPT, clock::IcHist}; +pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4); //======================= Custom mutator @@ -201,7 +55,6 @@ where manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { - let mut mymut : InterruptShifterMutator = InterruptShifterMutator::new(); let mut _input = state .corpus() .get(corpus_idx)? diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index 938e52b7ff..f4716649a6 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -15,8 +15,6 @@ pub mod observers; pub mod feedbacks; pub mod graph; pub mod schedulers; -pub mod mutation; -pub mod mutators; // #[cfg(feature = "fuzz_interrupt")] // pub const IRQ_INPUT_BYTES_NUMBER : u32 = 2; // Offset for interrupt bytes diff --git a/fuzzers/FRET/src/systemstate/mutation/mod.rs b/fuzzers/FRET/src/systemstate/mutation/mod.rs deleted file mode 100644 index 0b8b6741d2..0000000000 --- a/fuzzers/FRET/src/systemstate/mutation/mod.rs +++ /dev/null @@ -1,185 +0,0 @@ -//! Mutators mutate input during fuzzing. - -pub mod scheduled; -pub use scheduled::*; -pub mod mutations; -pub use mutations::*; - -use libafl::{ - bolts::tuples::{HasConstLen, Named}, - inputs::UsesInput, - Error, prelude::Testcase, - mutators::{MutationResult}, -}; - -// 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 -where - S: UsesInput, -{ - /// Mutate a given input - fn mutate( - &mut self, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result; - - /// Post-process given the outcome of the execution - fn post_exec( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option, - ) -> Result<(), Error> { - Ok(()) - } -} - -/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. -pub trait MutatorsTuple: HasConstLen -where - S: UsesInput, -{ - /// Runs the `mutate` function on all `Mutators` in this `Tuple`. - fn mutate_all( - &mut self, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result; - - /// Runs the `post_exec` function on all `Mutators` in this `Tuple`. - fn post_exec_all( - &mut self, - state: &mut S, - stage_idx: i32, - corpus_idx: Option, - ) -> Result<(), Error>; - - /// Gets the [`Mutator`] at the given index and runs the `mutate` function on it. - fn get_and_mutate( - &mut self, - index: usize, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result; - - /// Gets the [`Mutator`] at the given index and runs the `post_exec` function on it. - fn get_and_post_exec( - &mut self, - index: usize, - state: &mut S, - stage_idx: i32, - corpus_idx: Option, - ) -> Result<(), Error>; -} - -impl MutatorsTuple for () -where - S: UsesInput, -{ - fn mutate_all( - &mut self, - _state: &mut S, - _input: &mut Testcase, - _stage_idx: i32, - ) -> Result { - Ok(MutationResult::Skipped) - } - - fn post_exec_all( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option, - ) -> Result<(), Error> { - Ok(()) - } - - fn get_and_mutate( - &mut self, - _index: usize, - _state: &mut S, - _input: &mut Testcase, - _stage_idx: i32, - ) -> Result { - Ok(MutationResult::Skipped) - } - - fn get_and_post_exec( - &mut self, - _index: usize, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option, - ) -> Result<(), Error> { - Ok(()) - } -} - -impl MutatorsTuple for (Head, Tail) -where - Head: Mutator + Named, - Tail: MutatorsTuple, - S: UsesInput, -{ - fn mutate_all( - &mut self, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result { - let r = self.0.mutate(state, input, stage_idx)?; - if self.1.mutate_all(state, input, stage_idx)? == MutationResult::Mutated { - Ok(MutationResult::Mutated) - } else { - Ok(r) - } - } - - fn post_exec_all( - &mut self, - state: &mut S, - stage_idx: i32, - corpus_idx: Option, - ) -> Result<(), Error> { - self.0.post_exec(state, stage_idx, corpus_idx)?; - self.1.post_exec_all(state, stage_idx, corpus_idx) - } - - fn get_and_mutate( - &mut self, - index: usize, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result { - if index == 0 { - self.0.mutate(state, input, stage_idx) - } else { - self.1.get_and_mutate(index - 1, state, input, stage_idx) - } - } - - fn get_and_post_exec( - &mut self, - index: usize, - state: &mut S, - stage_idx: i32, - corpus_idx: Option, - ) -> Result<(), Error> { - if index == 0 { - self.0.post_exec(state, stage_idx, corpus_idx) - } else { - self.1 - .get_and_post_exec(index - 1, state, stage_idx, corpus_idx) - } - } -} \ No newline at end of file diff --git a/fuzzers/FRET/src/systemstate/mutation/mutations.rs b/fuzzers/FRET/src/systemstate/mutation/mutations.rs deleted file mode 100644 index fd28548caa..0000000000 --- a/fuzzers/FRET/src/systemstate/mutation/mutations.rs +++ /dev/null @@ -1,1189 +0,0 @@ -//! A wide variety of mutations used during fuzzing. - -extern crate alloc; -use alloc::{borrow::ToOwned, vec::Vec}; -use core::{ - cmp::{max, min}, - mem::size_of, -}; - -use libafl::{ - bolts::{rands::Rand, tuples::Named}, - corpus::Corpus, - inputs::{HasBytesVec, UsesInput}, - // mutators::{MutationResult, Mutator}, - state::{HasCorpus, HasMaxSize, HasRand}, - Error, prelude::Testcase, -}; - -use libafl::mutators::{MutationResult}; - -use crate::systemstate::mutation::Mutator; - -/// Mem move in the own vec -#[inline] -pub fn buffer_self_copy(data: &mut [T], from: usize, to: usize, len: usize) { - debug_assert!(!data.is_empty()); - debug_assert!(from + len <= data.len()); - debug_assert!(to + len <= data.len()); - if len != 0 && from != to { - let ptr = data.as_mut_ptr(); - unsafe { - core::ptr::copy(ptr.add(from), ptr.add(to), len); - } - } -} - -/// Mem move between vecs -#[inline] -pub fn buffer_copy(dst: &mut [T], src: &[T], from: usize, to: usize, len: usize) { - debug_assert!(!dst.is_empty()); - debug_assert!(!src.is_empty()); - debug_assert!(from + len <= src.len()); - debug_assert!(to + len <= dst.len()); - let dst_ptr = dst.as_mut_ptr(); - let src_ptr = src.as_ptr(); - if len != 0 { - unsafe { - core::ptr::copy(src_ptr.add(from), dst_ptr.add(to), len); - } - } -} - -/// A simple way to set buffer contents. -/// The compiler does the heavy lifting. -/// see -#[inline] -pub fn buffer_set(data: &mut [T], from: usize, len: usize, val: T) { - debug_assert!(from + len <= data.len()); - for p in &mut data[from..(from + len)] { - *p = val.clone(); - } -} - -/// The max value that will be added or subtracted during add mutations -pub const ARITH_MAX: u64 = 35; - -/// Interesting 8-bit values from AFL -pub const INTERESTING_8: [i8; 9] = [-128, -1, 0, 1, 16, 32, 64, 100, 127]; -/// Interesting 16-bit values from AFL -pub const INTERESTING_16: [i16; 19] = [ - -128, -1, 0, 1, 16, 32, 64, 100, 127, -32768, -129, 128, 255, 256, 512, 1000, 1024, 4096, 32767, -]; -/// Interesting 32-bit values from AFL -pub 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 -#[derive(Default, Debug)] -pub struct BitFlipMutator; - -impl Mutator for BitFlipMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - let bit = 1 << state.rand_mut().choose(0..8); - let byte = state.rand_mut().choose(input.bytes_mut()); - *byte ^= bit; - Ok(MutationResult::Mutated) - } - } -} - -impl Named for BitFlipMutator { - fn name(&self) -> &str { - "BitFlipMutator" - } -} - -impl BitFlipMutator { - /// Creates a new [`BitFlipMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Byteflip mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct ByteFlipMutator; - -impl Mutator for ByteFlipMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - *state.rand_mut().choose(input.bytes_mut()) ^= 0xff; - Ok(MutationResult::Mutated) - } - } -} - -impl Named for ByteFlipMutator { - fn name(&self) -> &str { - "ByteFlipMutator" - } -} - -impl ByteFlipMutator { - /// Creates a new [`ByteFlipMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Byte increment mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct ByteIncMutator; - -impl Mutator for ByteIncMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - let byte = state.rand_mut().choose(input.bytes_mut()); - *byte = byte.wrapping_add(1); - Ok(MutationResult::Mutated) - } - } -} - -impl Named for ByteIncMutator { - fn name(&self) -> &str { - "ByteIncMutator" - } -} - -impl ByteIncMutator { - /// Creates a new [`ByteIncMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Byte decrement mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct ByteDecMutator; - -impl Mutator for ByteDecMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - let byte = state.rand_mut().choose(input.bytes_mut()); - *byte = byte.wrapping_sub(1); - Ok(MutationResult::Mutated) - } - } -} - -impl Named for ByteDecMutator { - fn name(&self) -> &str { - "ByteDecMutator" - } -} - -impl ByteDecMutator { - /// Creates a a new [`ByteDecMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Byte negate mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct ByteNegMutator; - -impl Mutator for ByteNegMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - let byte = state.rand_mut().choose(input.bytes_mut()); - *byte = (!(*byte)).wrapping_add(1); - Ok(MutationResult::Mutated) - } - } -} - -impl Named for ByteNegMutator { - fn name(&self) -> &str { - "ByteNegMutator" - } -} - -impl ByteNegMutator { - /// Creates a new [`ByteNegMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Byte random mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct ByteRandMutator; - -impl Mutator for ByteRandMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().is_empty() { - Ok(MutationResult::Skipped) - } else { - let byte = state.rand_mut().choose(input.bytes_mut()); - *byte = state.rand_mut().next() as u8; - Ok(MutationResult::Mutated) - } - } -} - -impl Named for ByteRandMutator { - fn name(&self) -> &str { - "ByteRandMutator" - } -} - -impl ByteRandMutator { - /// Creates a new [`ByteRandMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -// Helper macro that defines the arithmetic addition/subtraction mutations where random slices -// within the input are treated as u8, u16, u32, or u64, then mutated in place. -macro_rules! add_mutator_impl { - ($name: ident, $size: ty) => { - /// Adds or subtracts a random value up to `ARITH_MAX` to a [`<$size>`] at a random place in the [`Vec`], in random byte order. - #[derive(Default, Debug)] - pub struct $name; - - #[allow(trivial_numeric_casts)] - impl Mutator for $name - where - S: UsesInput + HasRand, - S::Input: HasBytesVec, - { - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().len() < size_of::<$size>() { - Ok(MutationResult::Skipped) - } else { - // choose a random window of bytes (windows overlap) and convert to $size - let (index, bytes) = state - .rand_mut() - .choose(input.bytes().windows(size_of::<$size>()).enumerate()); - let val = <$size>::from_ne_bytes(bytes.try_into().unwrap()); - - // mutate - let num = 1 + state.rand_mut().below(ARITH_MAX) as $size; - let new_val = match state.rand_mut().below(4) { - 0 => val.wrapping_add(num), - 1 => val.wrapping_sub(num), - 2 => val.swap_bytes().wrapping_add(num).swap_bytes(), - _ => val.swap_bytes().wrapping_sub(num).swap_bytes(), - }; - - // set bytes to mutated value - let new_bytes = &mut input.bytes_mut()[index..index + size_of::<$size>()]; - new_bytes.copy_from_slice(&new_val.to_ne_bytes()); - Ok(MutationResult::Mutated) - } - } - } - - impl Named for $name { - fn name(&self) -> &str { - stringify!($name) - } - } - - impl $name { - /// Creates a new [`$name`]. - #[must_use] - pub fn new() -> Self { - Self - } - } - }; -} - -add_mutator_impl!(ByteAddMutator, u8); -add_mutator_impl!(WordAddMutator, u16); -add_mutator_impl!(DwordAddMutator, u32); -add_mutator_impl!(QwordAddMutator, u64); - -/////////////////////////// - -macro_rules! interesting_mutator_impl { - ($name: ident, $size: ty, $interesting: ident) => { - /// Inserts an interesting value at a random place in the input vector - #[derive(Default, Debug)] - pub struct $name; - - impl Mutator for $name - where - S: UsesInput + HasRand, - S::Input: HasBytesVec, - { - #[allow(clippy::cast_sign_loss)] - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - if input.bytes().len() < size_of::<$size>() { - Ok(MutationResult::Skipped) - } else { - let bytes = input.bytes_mut(); - let upper_bound = (bytes.len() + 1 - size_of::<$size>()) as u64; - let idx = state.rand_mut().below(upper_bound) as usize; - let val = *state.rand_mut().choose(&$interesting) as $size; - let new_bytes = match state.rand_mut().choose(&[0, 1]) { - 0 => val.to_be_bytes(), - _ => val.to_le_bytes(), - }; - bytes[idx..idx + size_of::<$size>()].copy_from_slice(&new_bytes); - Ok(MutationResult::Mutated) - } - } - } - - impl Named for $name { - fn name(&self) -> &str { - stringify!($name) - } - } - - impl $name { - /// Creates a new [`$name`]. - #[must_use] - pub fn new() -> Self { - Self - } - } - }; -} - -interesting_mutator_impl!(ByteInterestingMutator, u8, INTERESTING_8); -interesting_mutator_impl!(WordInterestingMutator, u16, INTERESTING_16); -interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32); - -/// Bytes delete mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesDeleteMutator; - -impl Mutator for BytesDeleteMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size <= 2 { - return Ok(MutationResult::Skipped); - } - - 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) - } -} - -impl Named for BytesDeleteMutator { - fn name(&self) -> &str { - "BytesDeleteMutator" - } -} - -impl BytesDeleteMutator { - /// Creates a new [`BytesDeleteMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes expand mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesExpandMutator; - -impl Mutator for BytesExpandMutator -where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let max_size = state.max_size(); - let size = input.bytes().len(); - 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 > max_size { - if max_size > size { - len = max_size - size; - } else { - return Ok(MutationResult::Skipped); - } - } - - input.bytes_mut().resize(size + len, 0); - buffer_self_copy(input.bytes_mut(), off, off + len, size - off); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesExpandMutator { - fn name(&self) -> &str { - "BytesExpandMutator" - } -} - -impl BytesExpandMutator { - /// Creates a new [`BytesExpandMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes insert mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesInsertMutator; - -impl Mutator for BytesInsertMutator -where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let max_size = state.max_size(); - let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - 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 > max_size { - if max_size > size { - len = max_size - size; - } else { - return Ok(MutationResult::Skipped); - } - } - - 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); - buffer_set(input.bytes_mut(), off, len, val); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesInsertMutator { - fn name(&self) -> &str { - "BytesInsertMutator" - } -} - -impl BytesInsertMutator { - /// Creates a new [`BytesInsertMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes random insert mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesRandInsertMutator; - -impl Mutator for BytesRandInsertMutator -where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let max_size = state.max_size(); - let size = input.bytes().len(); - 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 > max_size { - if max_size > size { - len = max_size - size; - } else { - return Ok(MutationResult::Skipped); - } - } - - let val = state.rand_mut().next() as u8; - - input.bytes_mut().resize(size + len, 0); - buffer_self_copy(input.bytes_mut(), off, off + len, size - off); - buffer_set(input.bytes_mut(), off, len, val); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesRandInsertMutator { - fn name(&self) -> &str { - "BytesRandInsertMutator" - } -} - -impl BytesRandInsertMutator { - /// Create a new [`BytesRandInsertMutator`] - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes set mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesSetMutator; - -impl Mutator for BytesSetMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - 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 = *state.rand_mut().choose(input.bytes()); - - buffer_set(input.bytes_mut(), off, len, val); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesSetMutator { - fn name(&self) -> &str { - "BytesSetMutator" - } -} - -impl BytesSetMutator { - /// Creates a new [`BytesSetMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes random set mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesRandSetMutator; - -impl Mutator for BytesRandSetMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - 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 = state.rand_mut().next() as u8; - - buffer_set(input.bytes_mut(), off, len, val); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesRandSetMutator { - fn name(&self) -> &str { - "BytesRandSetMutator" - } -} - -impl BytesRandSetMutator { - /// Creates a new [`BytesRandSetMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes copy mutation for inputs with a bytes vector -#[derive(Default, Debug)] -pub struct BytesCopyMutator; - -impl Mutator for BytesCopyMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size <= 1 { - return Ok(MutationResult::Skipped); - } - - 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); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesCopyMutator { - fn name(&self) -> &str { - "BytesCopyMutator" - } -} - -impl BytesCopyMutator { - /// Creates a new [`BytesCopyMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Bytes insert and self copy mutation for inputs with a bytes vector -#[derive(Debug, Default)] -pub struct BytesInsertCopyMutator { - tmp_buf: Vec, -} - -impl Mutator for BytesInsertCopyMutator -where - S: UsesInput + HasRand + HasMaxSize, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let max_size = state.max_size(); - let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - let off = state.rand_mut().below((size + 1) as u64) as usize; - let mut len = 1 + state.rand_mut().below(min(16, size as u64)) as usize; - - if size + len > max_size { - if max_size > size { - len = max_size - size; - } else { - return Ok(MutationResult::Skipped); - } - } - - let from = if size == len { - 0 - } else { - state.rand_mut().below((size - len) as u64) as usize - }; - - input.bytes_mut().resize(size + len, 0); - self.tmp_buf.resize(len, 0); - buffer_copy(&mut self.tmp_buf, input.bytes(), from, 0, len); - - buffer_self_copy(input.bytes_mut(), off, off + len, size - off); - buffer_copy(input.bytes_mut(), &self.tmp_buf, 0, off, len); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesInsertCopyMutator { - fn name(&self) -> &str { - "BytesInsertCopyMutator" - } -} - -impl BytesInsertCopyMutator { - /// Creates a new [`BytesInsertCopyMutator`]. - #[must_use] - pub fn new() -> Self { - Self::default() - } -} - -/// Bytes swap mutation for inputs with a bytes vector -#[derive(Debug, Default)] -pub struct BytesSwapMutator; - -impl Mutator for BytesSwapMutator -where - S: UsesInput + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size <= 1 { - return Ok(MutationResult::Skipped); - } - - 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); - buffer_copy(input.bytes_mut(), &tmp, 0, second, len); - - Ok(MutationResult::Mutated) - } -} - -impl Named for BytesSwapMutator { - fn name(&self) -> &str { - "BytesSwapMutator" - } -} - -impl BytesSwapMutator { - /// Creates a new [`BytesSwapMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Crossover insert mutation for inputs with a bytes vector -#[derive(Debug, Default)] -pub struct CrossoverInsertMutator; - -impl Mutator for CrossoverInsertMutator -where - S: HasCorpus + HasRand + HasMaxSize, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - - // We don't want to use the testcase we're already using for splicing - 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_size = state - .corpus() - .get(idx)? - .borrow_mut() - .load_input()? - .bytes() - .len(); - if other_size < 2 { - return Ok(MutationResult::Skipped); - } - - let max_size = state.max_size(); - 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 = 1 + 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 > max_size { - if max_size > size { - len = max_size - size; - } else { - return Ok(MutationResult::Skipped); - } - } - - input.bytes_mut().resize(size + len, 0); - buffer_self_copy(input.bytes_mut(), to, to + len, size - to); - buffer_copy(input.bytes_mut(), other.bytes(), from, to, len); - - Ok(MutationResult::Mutated) - } -} - -impl Named for CrossoverInsertMutator { - fn name(&self) -> &str { - "CrossoverInsertMutator" - } -} - -impl CrossoverInsertMutator { - /// Creates a new [`CrossoverInsertMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Crossover replace mutation for inputs with a bytes vector -#[derive(Debug, Default)] -pub struct CrossoverReplaceMutator; - -impl Mutator for CrossoverReplaceMutator -where - S: HasCorpus + HasRand, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - let size = input.bytes().len(); - if size == 0 { - return Ok(MutationResult::Skipped); - } - - // We don't want to use the testcase we're already using for splicing - 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_size = state - .corpus() - .get(idx)? - .borrow_mut() - .load_input()? - .bytes() - .len(); - if other_size < 2 { - return Ok(MutationResult::Skipped); - } - - 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; - - 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) - } -} - -impl Named for CrossoverReplaceMutator { - fn name(&self) -> &str { - "CrossoverReplaceMutator" - } -} - -impl CrossoverReplaceMutator { - /// Creates a new [`CrossoverReplaceMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -/// Returns the first and last diff position between the given vectors, stopping at the min len -fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { - let mut first_diff: i64 = -1; - let mut last_diff: i64 = -1; - for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() { - if this_el != other_el { - if first_diff < 0 { - first_diff = i as i64; - } - last_diff = i as i64; - } - } - - (first_diff, last_diff) -} - -/// Splice mutation for inputs with a bytes vector -#[derive(Debug, Default)] -pub struct SpliceMutator; - -impl Mutator for SpliceMutator -where - S: HasCorpus + HasRand, - S::Input: HasBytesVec, -{ - #[allow(clippy::cast_sign_loss)] - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase<::Input>, - _stage_idx: i32, - ) -> Result { - let mut input = _input.input_mut().as_mut().unwrap(); - // We don't want to use the testcase we're already using for splicing - 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 (first_diff, last_diff) = { - let mut other_testcase = state.corpus().get(idx)?.borrow_mut(); - let other = other_testcase.load_input()?; - - let mut counter: u32 = 0; - loop { - let (f, l) = locate_diffs(input.bytes(), other.bytes()); - - if f != l && f >= 0 && l >= 2 { - break (f as u64, l as u64); - } - if counter == 3 { - return Ok(MutationResult::Skipped); - } - counter += 1; - } - }; - - let split_at = state.rand_mut().between(first_diff, last_diff) 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().copied()); - - Ok(MutationResult::Mutated) - } -} - -impl Named for SpliceMutator { - fn name(&self) -> &str { - "SpliceMutator" - } -} - -impl SpliceMutator { - /// Creates a new [`SpliceMutator`]. - #[must_use] - pub fn new() -> Self { - Self - } -} - -// Converts a hex u8 to its u8 value: 'A' -> 10 etc. -fn from_hex(hex: u8) -> Result { - match hex { - 48..=57 => Ok(hex - 48), - 65..=70 => Ok(hex - 55), - 97..=102 => Ok(hex - 87), - _ => Err(Error::illegal_argument("Invalid hex character".to_owned())), - } -} - -/// Decodes a dictionary token: 'foo\x41\\and\"bar' -> 'fooA\and"bar' -pub fn str_decode(item: &str) -> Result, Error> { - let mut token: Vec = Vec::new(); - let item: Vec = item.as_bytes().to_vec(); - let backslash: u8 = 92; // '\\' - let mut take_next: bool = false; - let mut take_next_two: u32 = 0; - let mut decoded: u8 = 0; - - for c in item { - if take_next_two == 1 { - decoded = from_hex(c)? << 4; - take_next_two = 2; - } else if take_next_two == 2 { - decoded += from_hex(c)?; - token.push(decoded); - take_next_two = 0; - } else if c != backslash || take_next { - if take_next && (c == 120 || c == 88) { - take_next_two = 1; - } else { - token.push(c); - } - take_next = false; - } else { - take_next = true; - } - } - - Ok(token) -} diff --git a/fuzzers/FRET/src/systemstate/mutation/scheduled.rs b/fuzzers/FRET/src/systemstate/mutation/scheduled.rs deleted file mode 100644 index 04c5da3216..0000000000 --- a/fuzzers/FRET/src/systemstate/mutation/scheduled.rs +++ /dev/null @@ -1,421 +0,0 @@ -//! The `ScheduledMutator` schedules multiple mutations internally. - -extern crate alloc; -use alloc::{string::String, vec::Vec}; -use core::{ - fmt::{self, Debug}, - marker::PhantomData, -}; - -use serde::{Deserialize, Serialize}; - -pub use crate::systemstate::mutation::{ - mutations::*, - Mutator,MutatorsTuple, -}; -use libafl::{ - bolts::{ - rands::Rand, - tuples::{tuple_list, tuple_list_type, NamedTuple}, - AsMutSlice, AsSlice, - }, - corpus::Corpus, - inputs::UsesInput, - mutators::{MutationResult}, - state::{HasCorpus, HasMetadata, HasRand, State}, - Error, prelude::{TokenInsert, TokenReplace, Testcase}, -}; - -/// The metadata placed in a [`crate::corpus::Testcase`] by a [`LoggerScheduledMutator`]. -#[derive(Debug, Serialize, Deserialize)] -pub struct LogMutationMetadata { - /// A list of logs - pub list: Vec, -} - -libafl::impl_serdeany!(LogMutationMetadata); - -impl AsSlice for LogMutationMetadata { - type Entry = String; - #[must_use] - fn as_slice(&self) -> &[String] { - self.list.as_slice() - } -} -impl AsMutSlice for LogMutationMetadata { - type Entry = String; - #[must_use] - fn as_mut_slice(&mut self) -> &mut [String] { - self.list.as_mut_slice() - } -} - -impl LogMutationMetadata { - /// Creates new [`struct@LogMutationMetadata`]. - #[must_use] - pub fn new(list: Vec) -> Self { - Self { list } - } -} - -/// A [`Mutator`] that composes multiple mutations into one. -pub trait ComposedByMutations -where - MT: MutatorsTuple, - S: UsesInput, -{ - /// Get the mutations - fn mutations(&self) -> &MT; - - /// Get the mutations (mutable) - fn mutations_mut(&mut self) -> &mut MT; -} - -/// A [`Mutator`] scheduling multiple [`Mutator`]s for an input. -pub trait ScheduledMutator: ComposedByMutations + Mutator -where - MT: MutatorsTuple, - S: UsesInput, -{ - /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, input: &Testcase) -> u64; - - /// Get the next mutation to apply - fn schedule(&self, state: &mut S, input: &Testcase) -> usize; - - /// New default implementation for mutate. - /// Implementations must forward mutate() to this method - fn scheduled_mutate( - &mut self, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result { - let mut r = MutationResult::Skipped; - let num = self.iterations(state, input); - for _ in 0..num { - let idx = self.schedule(state, input); - let outcome = self - .mutations_mut() - .get_and_mutate(idx, state, input, stage_idx)?; - if outcome == MutationResult::Mutated { - r = MutationResult::Mutated; - } - } - Ok(r) - } -} - -/// A [`Mutator`] that schedules one of the embedded mutations on each call. -pub struct StdScheduledMutator -where - MT: MutatorsTuple, - S: State + HasRand, -{ - mutations: MT, - max_stack_pow: u64, - phantom: PhantomData, -} - -impl Debug for StdScheduledMutator -where - MT: MutatorsTuple, - S: State + 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::() - ) - } -} - -impl Mutator for StdScheduledMutator -where - MT: MutatorsTuple, - S: State + HasRand, -{ - #[inline] - fn mutate( - &mut self, - state: &mut S, - input: &mut Testcase, - stage_idx: i32, - ) -> Result { - self.scheduled_mutate(state, input, stage_idx) - } -} - -impl ComposedByMutations for StdScheduledMutator -where - MT: MutatorsTuple, - S: State + HasRand, -{ - /// Get the mutations - #[inline] - fn mutations(&self) -> &MT { - &self.mutations - } - - // Get the mutations (mutable) - #[inline] - fn mutations_mut(&mut self) -> &mut MT { - &mut self.mutations - } -} - -impl ScheduledMutator for StdScheduledMutator -where - MT: MutatorsTuple, - S: State + HasRand, -{ - /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &Testcase) -> u64 { - 1 << (1 + state.rand_mut().below(self.max_stack_pow)) - } - - /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &Testcase) -> usize { - debug_assert!(!self.mutations().is_empty()); - state.rand_mut().below(self.mutations().len() as u64) as usize - } -} - -impl StdScheduledMutator -where - MT: MutatorsTuple, - S: State + HasRand, -{ - /// Create a new [`StdScheduledMutator`] instance specifying mutations - pub fn new(mutations: MT) -> Self { - StdScheduledMutator { - mutations, - max_stack_pow: 7, - phantom: PhantomData, - } - } - - /// Create a new [`StdScheduledMutator`] instance specifying mutations and the maximun number of iterations - pub fn with_max_stack_pow(mutations: MT, max_stack_pow: u64) -> Self { - StdScheduledMutator { - mutations, - max_stack_pow, - phantom: PhantomData, - } - } -} - -/// Tuple type of the mutations that compose the Havoc mutator -pub type HavocMutationsType = tuple_list_type!( - BitFlipMutator, - ByteFlipMutator, - ByteIncMutator, - ByteDecMutator, - ByteNegMutator, - ByteRandMutator, - ByteAddMutator, - WordAddMutator, - DwordAddMutator, - QwordAddMutator, - ByteInterestingMutator, - WordInterestingMutator, - DwordInterestingMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesDeleteMutator, - BytesExpandMutator, - BytesInsertMutator, - BytesRandInsertMutator, - BytesSetMutator, - BytesRandSetMutator, - BytesCopyMutator, - BytesInsertCopyMutator, - BytesSwapMutator, - CrossoverInsertMutator, - CrossoverReplaceMutator, -); - -/// Get the mutations that compose the Havoc mutator -#[must_use] -pub fn havoc_mutations() -> HavocMutationsType { - tuple_list!( - BitFlipMutator::new(), - ByteFlipMutator::new(), - ByteIncMutator::new(), - ByteDecMutator::new(), - ByteNegMutator::new(), - ByteRandMutator::new(), - ByteAddMutator::new(), - WordAddMutator::new(), - DwordAddMutator::new(), - QwordAddMutator::new(), - ByteInterestingMutator::new(), - WordInterestingMutator::new(), - DwordInterestingMutator::new(), - BytesDeleteMutator::new(), - BytesDeleteMutator::new(), - BytesDeleteMutator::new(), - BytesDeleteMutator::new(), - BytesExpandMutator::new(), - BytesInsertMutator::new(), - BytesRandInsertMutator::new(), - BytesSetMutator::new(), - BytesRandSetMutator::new(), - BytesCopyMutator::new(), - BytesInsertCopyMutator::new(), - BytesSwapMutator::new(), - CrossoverInsertMutator::new(), - CrossoverReplaceMutator::new(), - ) -} - -/// Get the mutations that uses the Tokens metadata -#[must_use] -pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) { - tuple_list!(TokenInsert::new(), TokenReplace::new(),) -} - -/// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`]. -pub struct LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: UsesInput + HasRand + HasCorpus, - SM: ScheduledMutator, -{ - scheduled: SM, - mutation_log: Vec, - phantom: PhantomData<(MT, S)>, -} - -impl Debug for LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: UsesInput + 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>() - ) - } -} - -impl Mutator for LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, -{ - fn mutate( - &mut self, - state: &mut S, - input: &mut Testcase<::Input>, - stage_idx: i32, - ) -> Result { - self.scheduled_mutate(state, input, stage_idx) - } - - fn post_exec( - &mut self, - state: &mut S, - _stage_idx: i32, - corpus_idx: Option, - ) -> Result<(), Error> { - if let Some(idx) = corpus_idx { - let mut testcase = (*state.corpus_mut().get(idx)?).borrow_mut(); - let mut log = Vec::::new(); - while let Some(idx) = self.mutation_log.pop() { - let name = String::from(self.scheduled.mutations().name(idx).unwrap()); // TODO maybe return an Error on None - log.push(name); - } - let meta = LogMutationMetadata::new(log); - testcase.add_metadata(meta); - }; - // Always reset the log for each run - self.mutation_log.clear(); - Ok(()) - } -} - -impl ComposedByMutations for LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, -{ - #[inline] - fn mutations(&self) -> &MT { - self.scheduled.mutations() - } - - #[inline] - fn mutations_mut(&mut self) -> &mut MT { - self.scheduled.mutations_mut() - } -} - -impl ScheduledMutator for LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, -{ - /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &Testcase<::Input>) -> u64 { - 1 << (1 + state.rand_mut().below(6)) - } - - /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &Testcase<::Input>) -> usize { - debug_assert!(!self.scheduled.mutations().is_empty()); - state - .rand_mut() - .below(self.scheduled.mutations().len() as u64) as usize - } - - fn scheduled_mutate( - &mut self, - state: &mut S, - input: &mut Testcase<::Input>, - stage_idx: i32, - ) -> Result { - let mut r = MutationResult::Skipped; - let num = self.iterations(state, input); - self.mutation_log.clear(); - for _ in 0..num { - let idx = self.schedule(state, input); - self.mutation_log.push(idx); - let outcome = self - .mutations_mut() - .get_and_mutate(idx, state, input, stage_idx)?; - if outcome == MutationResult::Mutated { - r = MutationResult::Mutated; - } - } - Ok(r) - } -} - -impl LoggerScheduledMutator -where - MT: MutatorsTuple + NamedTuple, - S: State + HasRand + HasCorpus, - SM: ScheduledMutator, -{ - /// Create a new [`StdScheduledMutator`] instance without mutations and corpus - pub fn new(scheduled: SM) -> Self { - Self { - scheduled, - mutation_log: vec![], - phantom: PhantomData, - } - } -} - - diff --git a/fuzzers/FRET/src/systemstate/mutators.rs b/fuzzers/FRET/src/systemstate/mutators.rs deleted file mode 100644 index 4b26658394..0000000000 --- a/fuzzers/FRET/src/systemstate/mutators.rs +++ /dev/null @@ -1,253 +0,0 @@ -use crate::fuzzer::DO_NUM_INTERRUPT; -use crate::systemstate::mutation::Mutator; -use crate::systemstate::graph::SysGraphMetadata; -use crate::systemstate::graph::SysGraphNode; -// use crate::systemstate::IRQ_INPUT_OFFSET; -// use crate::systemstate::IRQ_INPUT_BYTES_NUMBER; -use crate::systemstate::graph::SysGraphFeedbackState; -use libafl::inputs::HasBytesVec; -use libafl::bolts::rands::RandomSeed; -use libafl::bolts::rands::StdRand; -use libafl::prelude::Testcase; -use libafl::mutators::MutationResult; -use libafl::prelude::Corpus; -use libafl::prelude::UsesInput; -use core::marker::PhantomData; -use std::cmp::max; -use std::cmp::min; -use libafl::state::HasCorpus; -use libafl::state::HasSolutions; -use libafl::state::HasRand; - -use libafl::bolts::tuples::MatchName; -use libafl::bolts::tuples::Named; -use libafl::Error; -use libafl::{inputs::Input, state::HasMetadata}; - -use super::FreeRTOSSystemStateMetadata; -use super::RefinedFreeRTOSSystemState; - -use libafl::bolts::rands::Rand; - -pub const MINIMUM_INTER_ARRIVAL_TIME : u32 = 700 * 1000 * (1 << 4); - -//=============================== Interrupt -/// Sets up the interrupt to a random block in the trace. Works for both state and graph metadata -pub struct InterruptShifterMutator -where - S: UsesInput, -{ - phantom: PhantomData, -} -impl InterruptShifterMutator -where - S: UsesInput, -{ - pub fn new() -> Self { - InterruptShifterMutator{phantom: PhantomData} - } -} -impl Mutator for InterruptShifterMutator -where - S: UsesInput + HasRand + HasMetadata + HasCorpus, - S::Input: HasBytesVec, -{ - fn mutate( - &mut self, - state: &mut S, - _input: &mut Testcase, - _stage_idx: i32 - ) -> Result - { - // need our own random generator, because borrowing rules - let mut myrand = StdRand::new(); - let mut target_bytes : Vec = vec![]; - { - let input = _input.input_mut().as_ref().unwrap(); - let tmp = &mut state.rand_mut(); - myrand.set_seed(tmp.next()); - target_bytes = input.bytes().to_vec(); - } - - // produce a slice of absolute interrupt times - let mut interrupt_offsets : [u32; 32] = [0u32; 32]; - let mut num_interrupts : usize = 0; - { - let mut start_tick : u32 = 0; - for i in 0..DO_NUM_INTERRUPT { - let mut t : [u8; 4] = [0,0,0,0]; - if target_bytes.len() > (i+1)*4 { - for j in 0 as usize..4 as usize { - t[j]=target_bytes[i*4+j]; - } - if i == 0 { - start_tick = u32::from_le_bytes(t); - } else { - start_tick = u32::saturating_add(start_tick,max(MINIMUM_INTER_ARRIVAL_TIME,u32::from_le_bytes(t))); - } - interrupt_offsets[i] = start_tick; - num_interrupts = i+1; - } - } - } - - // println!("Vor Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec()); - // let num_i = min(target_bytes.len() / 4, DO_NUM_INTERRUPT); - let mut suffix = target_bytes.split_off(4 * num_interrupts); - let mut prefix : Vec<[u8; 4]> = vec![]; - // let mut suffix : Vec = vec![]; - // #[cfg(feature = "feed_systemtrace")] - { - let tmp = _input.metadata().get::(); - if tmp.is_none() { - return Ok(MutationResult::Skipped); - } - let trace = tmp.expect("FreeRTOSSystemStateMetadata not found"); - - // calculate hits and identify snippets - let mut last_m = false; - let mut marks : Vec<(&RefinedFreeRTOSSystemState, usize, usize)>= vec![]; // 1: got interrupted, 2: interrupt handler - for i in 0..trace.inner.len() { - let curr = &trace.inner[i]; - let m = interrupt_offsets[0..num_interrupts].iter().any(|x| (curr.start_tick..curr.end_tick).contains(&(*x as u64))); - if m { - marks.push((curr, i, 1)); - // println!("1: {}",curr.current_task.task_name); - } else if last_m { - marks.push((curr, i, 2)); - // println!("2: {}",curr.current_task.task_name); - } else { - marks.push((curr, i, 0)); - } - last_m = m; - } - for i in 0..num_interrupts { - // bounds based on minimum inter-arrival time - let mut lb = 0; - let mut ub : u32 = marks[marks.len()-1].0.end_tick.try_into().expect("ticks > u32"); - if i > 0 { - lb = interrupt_offsets[i-1]+MINIMUM_INTER_ARRIVAL_TIME; - } - if i < num_interrupts-1 { - ub = interrupt_offsets[i+1]-MINIMUM_INTER_ARRIVAL_TIME; - } - // get old hit and handler - let old_hit = marks.iter().filter( - |x| x.0.start_tick < (interrupt_offsets[i] as u64) && (interrupt_offsets[i] as u64) < x.0.end_tick - ).next(); - let old_handler = match old_hit { - Some(s) => if s.1 < num_interrupts-1 && s.1 < marks.len()-1 { - Some(marks[s.1+1]) - } else {None}, - None => None - }; - // find reachable alternatives - let alternatives : Vec<_> = marks.iter().filter(|x| - ( - x.0.start_tick < (lb as u64) && (lb as u64) < x.0.end_tick - || x.0.start_tick < (ub as u64) && (ub as u64) < x.0.end_tick ) - ).collect(); - // in cases there are no alternatives - if alternatives.len() == 0 { - if old_hit.is_none() { - // choose something random - let untouched : Vec<_> = marks.iter().filter( - |x| x.2 == 0 - ).collect(); - let tmp = interrupt_offsets[i]; - let choice = myrand.choose(untouched); - interrupt_offsets[i] = myrand.between(choice.0.start_tick, choice.0.end_tick) - .try_into().expect("tick > u32"); - // println!("no alternatives, choose random i: {} {} -> {}",i,tmp,interrupt_offsets[i]); - continue; - } else { - // do nothing - // println!("no alternatives, do nothing i: {} {}",i,interrupt_offsets[i]); - continue; - } - } - let replacement = myrand.choose(alternatives); - if (old_hit.map_or(false, |x| x == replacement)) { - // use the old value - // println!("chose old value, do nothing i: {} {}",i,interrupt_offsets[i]); - continue; - } else { - let extra = if (old_hit.map_or(false, |x| x.1 < replacement.1)) { - // move futher back, respect old_handler - old_handler.map_or(0, |x| x.0.end_tick - x.0.start_tick) - } else { 0 }; - let tmp = interrupt_offsets[i]; - interrupt_offsets[i] = (myrand.between(replacement.0.start_tick, - replacement.0.end_tick) + extra).try_into().expect("ticks > u32"); - // println!("chose new alternative, i: {} {} -> {}",i,tmp, interrupt_offsets[i]); - } - } - // println!("Mutator: {:?}", interrupt_offsets[0..num_interrupts].to_vec()); - let mut numbers : Vec = interrupt_offsets[0..num_interrupts].to_vec(); - numbers.sort(); - let mut start : u32 = 0; - for i in 0..numbers.len() { - let tmp = numbers[i]; - numbers[i] = numbers[i]-start; - start = tmp; - } - for i in 0..numbers.len() { - prefix.push(u32::to_le_bytes(numbers[i])); - } - } - // #[cfg(feature = "sched_state")] - // { - // let feedbackstate = state - // .feedback_states() - // .match_name::("SysMap") - // .unwrap(); - // let g = &feedbackstate.graph; - // let tmp = state.metadata().get::(); - // if tmp.is_none() { // if there are no metadata it was probably not interesting anyways - // return Ok(MutationResult::Skipped); - // } - // let trace = tmp.expect("SysGraphMetadata not found"); - // let target_block : &SysGraphNode = &g[*myrand.choose(trace.inner.iter())]; - // target_tick = match target_block.variants.iter().find(|x| &x.input == target_bytes) { - // Some(s) => myrand.between(s.start_tick,s.end_tick)-IRQ_INPUT_OFFSET as u64, - // None => myrand.between(target_block.variants[0].start_tick,target_block.variants[0].end_tick)-IRQ_INPUT_OFFSET as u64, - // }; - - // } - - // calculate ranges, alternative hits - // move snippets - - let mut n = [prefix.concat(), suffix].concat(); - let input = _input.input_mut().as_mut().unwrap(); - input.bytes_mut().clear(); - input.bytes_mut().append(&mut n); - return Ok(MutationResult::Mutated); - // if target_bytes.len() > IRQ_INPUT_BYTES_NUMBER as usize && IRQ_INPUT_BYTES_NUMBER > 0 { - // for i in 0..IRQ_INPUT_BYTES_NUMBER as usize { - // target_bytes[i] = u64::to_le_bytes(target_tick)[i]; - // } - // return Ok(MutationResult::Mutated); - // } else { - // return Ok(MutationResult::Skipped); - // } - } - - fn post_exec( - &mut self, - _state: &mut S, - _stage_idx: i32, - _corpus_idx: Option - ) -> Result<(), Error> { - Ok(()) - } -} - -impl Named for InterruptShifterMutator -where - S: UsesInput, -{ - fn name(&self) -> &str { - "InterruptShifterMutator" - } -} \ No newline at end of file