diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index c6231c628d..daa9211d07 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -254,6 +254,7 @@ jobs: - ./fuzzers/baby/baby_fuzzer_grimoire - ./fuzzers/baby/baby_fuzzer_gramatron - ./fuzzers/baby/baby_fuzzer + - ./fuzzers/baby/baby_fuzzer_custom_input - ./fuzzers/baby/baby_fuzzer_nautilus # - ./fuzzers/baby/backtrace_baby_fuzzers - ./fuzzers/baby/baby_fuzzer_unicode diff --git a/fuzzers/baby/baby_fuzzer/src/main.rs b/fuzzers/baby/baby_fuzzer/src/main.rs index 2c22ae2f97..36f7ca94bd 100644 --- a/fuzzers/baby/baby_fuzzer/src/main.rs +++ b/fuzzers/baby/baby_fuzzer/src/main.rs @@ -14,7 +14,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/baby_fuzzer_custom_input/Cargo.toml b/fuzzers/baby/baby_fuzzer_custom_input/Cargo.toml new file mode 100644 index 0000000000..e27cbfe32e --- /dev/null +++ b/fuzzers/baby/baby_fuzzer_custom_input/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "baby_fuzzer_custom_input" +version = "0.1.0" +authors = ["Valentin Huber "] +edition = "2021" + +[features] +default = ["simple_interface"] +simple_interface = [] + +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +lto = true +codegen-units = 1 +opt-level = 3 +debug = true + +[dependencies] +libafl = { path = "../../../libafl/" } +libafl_bolts = { path = "../../../libafl_bolts/" } +serde = "*" diff --git a/fuzzers/baby/baby_fuzzer_custom_input/README.md b/fuzzers/baby/baby_fuzzer_custom_input/README.md new file mode 100644 index 0000000000..99514c9b33 --- /dev/null +++ b/fuzzers/baby/baby_fuzzer_custom_input/README.md @@ -0,0 +1,7 @@ +# Baby fuzzer + +This is a minimalistic fuzzer demonstrating how to employ mapping mutators to use default mutators on custom inputs. Custom inputs are necessary when the input to your program is a combination of parts, especially when those parts have different data types. Check multipart inputs if you have an input consisting of multiple parts of the same datatype and you don't need your mutation scheduler to be able to select which mutation is performed on which part. + +The fuzzer runs on a single core until a crash occurs and then exits. The tested program is a simple Rust function without any instrumentation. For real fuzzing, you will want to add some sort to add coverage or other feedback. + +You can run this example using `cargo run`. \ No newline at end of file diff --git a/fuzzers/baby/baby_fuzzer_custom_input/src/input.rs b/fuzzers/baby/baby_fuzzer_custom_input/src/input.rs new file mode 100644 index 0000000000..d6ffe0f477 --- /dev/null +++ b/fuzzers/baby/baby_fuzzer_custom_input/src/input.rs @@ -0,0 +1,147 @@ +use std::{ + borrow::Cow, + hash::{DefaultHasher, Hash, Hasher}, +}; + +use libafl::{ + corpus::CorpusId, + generators::Generator, + inputs::{BytesInput, HasTargetBytes, Input, MutVecInput}, + mutators::{MutationResult, Mutator}, + prelude::RandBytesGenerator, + state::HasRand, + Error, SerdeAny, +}; +use libafl_bolts::{rands::Rand, Named}; +use serde::{Deserialize, Serialize}; + +/// The custom [`Input`] type used in this example, consisting of a byte array part, a byte array that is not always present, and a boolean +/// +/// Imagine these could be used to model command line arguments for a bash command, where +/// - `byte_array` is binary data that is always needed like what is passed to stdin, +/// - `optional_byte_array` is binary data passed as a command line arg, and it is only passed if it is not `None` in the input, +/// - `boolean` models the presence or absence of a command line flag that does not require additional data +#[derive(Serialize, Deserialize, Clone, Debug, Hash, SerdeAny)] +pub struct CustomInput { + pub byte_array: Vec, + pub optional_byte_array: Option>, + pub boolean: bool, +} + +/// Hash-based implementation +impl Input for CustomInput { + fn generate_name(&self, _id: Option) -> String { + let mut hasher = DefaultHasher::new(); + self.hash(&mut hasher); + format!("{:016x}", hasher.finish()) + } +} + +impl CustomInput { + /// Returns a mutable reference to the byte array + pub fn byte_array_mut(&mut self) -> MutVecInput<'_> { + (&mut self.byte_array).into() + } + + /// Returns an immutable reference to the byte array wrapped in [`Some`] + pub fn byte_array_optional<'a>(&'a self) -> &'a [u8] { + &self.byte_array + } + + /// Returns a mutable reference to the optional byte array + pub fn optional_byte_array_mut(&mut self) -> Option> { + self.optional_byte_array.as_mut().map(|e| e.into()) + } + + /// Returns an immutable reference to the optional byte array + pub fn optional_byte_array_optional<'a>(&'a self) -> Option<&'a [u8]> { + self.optional_byte_array.as_deref() + } +} + +/// A generator for [`CustomInput`] used in this example +pub struct CustomInputGenerator { + pub max_len: usize, +} + +impl CustomInputGenerator { + /// Creates a new [`CustomInputGenerator`] + pub fn new(max_len: usize) -> Self { + Self { max_len } + } +} + +impl Generator for CustomInputGenerator +where + S: HasRand, +{ + fn generate(&mut self, state: &mut S) -> Result { + let mut generator = RandBytesGenerator::new(self.max_len); + + let byte_array = generator.generate(state).unwrap().target_bytes().into(); + let optional_byte_array = state + .rand_mut() + .coinflip(0.5) + .then(|| generator.generate(state).unwrap().target_bytes().into()); + let boolean = state.rand_mut().coinflip(0.5); + + Ok(CustomInput { + byte_array, + optional_byte_array, + boolean, + }) + } +} + +/// [`Mutator`] that toggles the optional byte array of a [`CustomInput`], i.e. sets it to [`None`] if it is not, and to a random byte array if it is [`None`] +pub struct ToggleOptionalByteArrayMutator { + generator: G, +} + +impl ToggleOptionalByteArrayMutator> +where + S: HasRand, +{ + /// Creates a new [`ToggleOptionalByteArrayMutator`] + pub fn new(length: usize) -> Self { + Self { + generator: RandBytesGenerator::new(length), + } + } +} + +impl Mutator for ToggleOptionalByteArrayMutator +where + S: HasRand, + G: Generator, +{ + fn mutate(&mut self, state: &mut S, input: &mut CustomInput) -> Result { + input.optional_byte_array = match input.optional_byte_array { + None => Some(self.generator.generate(state)?.target_bytes().into()), + Some(_) => None, + }; + Ok(MutationResult::Mutated) + } +} + +impl Named for ToggleOptionalByteArrayMutator { + fn name(&self) -> &Cow<'static, str> { + &Cow::Borrowed("ToggleOptionalByteArrayMutator") + } +} + +/// [`Mutator`] that toggles the boolean field in a [`CustomInput`] +pub struct ToggleBooleanMutator; + +impl Mutator for ToggleBooleanMutator { + fn mutate(&mut self, _state: &mut S, input: &mut CustomInput) -> Result { + input.boolean = !input.boolean; + Ok(MutationResult::Mutated) + } +} + +impl Named for ToggleBooleanMutator { + fn name(&self) -> &Cow<'static, str> { + &Cow::Borrowed("ToggleBooleanMutator") + } +} diff --git a/fuzzers/baby/baby_fuzzer_custom_input/src/main.rs b/fuzzers/baby/baby_fuzzer_custom_input/src/main.rs new file mode 100644 index 0000000000..7e3c83dcea --- /dev/null +++ b/fuzzers/baby/baby_fuzzer_custom_input/src/main.rs @@ -0,0 +1,206 @@ +mod input; + +#[cfg(windows)] +use std::ptr::write_volatile; +use std::{path::PathBuf, ptr::write}; + +use input::{ + CustomInput, CustomInputGenerator, ToggleBooleanMutator, ToggleOptionalByteArrayMutator, +}; +#[cfg(feature = "simple_interface")] +use libafl::mutators::havoc_mutations::{mapped_havoc_mutations, optional_mapped_havoc_mutations}; +use libafl::{ + corpus::{InMemoryCorpus, OnDiskCorpus}, + events::SimpleEventManager, + executors::{inprocess::InProcessExecutor, ExitKind}, + feedbacks::{CrashFeedback, MaxMapFeedback}, + fuzzer::{Fuzzer, StdFuzzer}, + monitors::SimpleMonitor, + mutators::scheduled::StdScheduledMutator, + observers::StdMapObserver, + schedulers::QueueScheduler, + stages::mutational::StdMutationalStage, + state::StdState, +}; +use libafl_bolts::{ + current_nanos, + rands::StdRand, + tuples::{tuple_list, Merge, Prepend}, +}; +#[cfg(not(feature = "simple_interface"))] +use { + libafl::{ + inputs::MutVecInput, + mutators::{ + havoc_mutations::{havoc_crossover_with_corpus_mapper, havoc_mutations_no_crossover}, + mapping::{ToMappedInputFunctionMappingMutatorMapper, ToOptionMappingMutatorMapper}, + }, + }, + libafl_bolts::tuples::Map, +}; + +/// Coverage map with explicit assignments due to the lack of instrumentation +static mut SIGNALS: [u8; 16] = [0; 16]; +static mut SIGNALS_PTR: *mut u8 = unsafe { SIGNALS.as_mut_ptr() }; + +/// Assign a signal to the signals map +fn signals_set(idx: usize) { + if idx > 2 { + println!("Setting signal: {idx}"); + } + unsafe { write(SIGNALS_PTR.add(idx), 1) }; +} + +#[allow(clippy::similar_names, clippy::manual_assert)] +pub fn main() { + // The closure that we want to fuzz + // The pseudo program under test uses all parts of the custom input + // We are manually setting bytes in a pseudo coverage map to guide the fuzzer + let mut harness = |input: &CustomInput| { + signals_set(0); + if input.byte_array == vec![b'a'] { + signals_set(1); + if input.optional_byte_array == Some(vec![b'b']) { + signals_set(2); + if input.boolean { + #[cfg(unix)] + panic!("Artificial bug triggered =)"); + + // panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler. + // Here we make it raise STATUS_ACCESS_VIOLATION instead. + // Extending the windows exception handler is a TODO. Maybe we can refer to what winafl code does. + // https://github.com/googleprojectzero/winafl/blob/ea5f6b85572980bb2cf636910f622f36906940aa/winafl.c#L728 + #[cfg(windows)] + unsafe { + write_volatile(0 as *mut u32, 0); + } + } + } + } + ExitKind::Ok + }; + + // Create an observation channel using the signals map + let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; + + // Feedback to rate the interestingness of an input + let mut feedback = MaxMapFeedback::new(&observer); + + // A feedback to choose if an input is a solution or not + let mut objective = CrashFeedback::new(); + + // create a State from scratch + let mut state = StdState::new( + // RNG + StdRand::with_seed(current_nanos()), + // Corpus that will be evolved, we keep it in memory for performance + InMemoryCorpus::new(), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), + // States of the feedbacks. + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); + + // The Monitor trait define how the fuzzer stats are displayed to the user + let mon = SimpleMonitor::new(|s| println!("{s}")); + + // The event manager handle the various events generated during the fuzzing loop + // such as the notification of the addition of a new item to the corpus + let mut mgr = SimpleEventManager::new(mon); + + // A queue policy to get testcasess from the corpus + let scheduler = QueueScheduler::new(); + + // A fuzzer with feedbacks and a corpus scheduler + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + + // Create the executor for an in-process function with just one observer + let mut executor = InProcessExecutor::new( + &mut harness, + tuple_list!(observer), + &mut fuzzer, + &mut state, + &mut mgr, + ) + .expect("Failed to create the Executor"); + + // Generator of printable bytearrays of max size 32 + let mut generator = CustomInputGenerator::new(1); + + // Generate 8 initial inputs + state + .generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8) + .expect("Failed to generate the initial corpus"); + + #[cfg(feature = "simple_interface")] + let (mapped_mutators, optional_mapped_mutators) = { + // Creating mutators that will operate on input.byte_array + let mapped_mutators = mapped_havoc_mutations( + CustomInput::byte_array_mut, + CustomInput::byte_array_optional, + ); + + // Creating mutators that will operate on input.optional_byte_array + let optional_mapped_mutators = optional_mapped_havoc_mutations( + CustomInput::optional_byte_array_mut, + CustomInput::optional_byte_array_optional, + ); + (mapped_mutators, optional_mapped_mutators) + }; + + #[cfg(not(feature = "simple_interface"))] + let (mapped_mutators, optional_mapped_mutators) = { + // Creating mutators that will operate on input.byte_array + // For now, due to a limitation in lifetime management (see the MappedInput trait), + // the types have to be partially specified + let mapped_mutators = havoc_mutations_no_crossover() + .merge(havoc_crossover_with_corpus_mapper( + &CustomInput::byte_array_optional, + )) + .map(ToMappedInputFunctionMappingMutatorMapper::< + _, + MutVecInput<'_>, + >::new(CustomInput::byte_array_mut)); + + // Creating mutators that will operate on input.optional_byte_array + // For now, due to a limitation in lifetime management (see the MappedInput trait), + // the types have to be partially specified + let optional_mapped_mutators = havoc_mutations_no_crossover() + .merge(havoc_crossover_with_corpus_mapper( + &CustomInput::optional_byte_array_optional, + )) + .map(ToOptionMappingMutatorMapper) + .map(ToMappedInputFunctionMappingMutatorMapper::new( + CustomInput::optional_byte_array_mut, + )); + + (mapped_mutators, optional_mapped_mutators) + }; + + // Merging multiple lists of mutators that mutate a sub-part of the custom input + // This collection could be expanded with default or custom mutators as needed for the input + let mutators = tuple_list!() + // First, mutators for the simple byte array + .merge(mapped_mutators) + // Then, mutators for the optional byte array, these return MutationResult::Skipped if the part is not present + .merge(optional_mapped_mutators) + // A custom mutator that sets the optional byte array to None if present, and generates a random byte array of length 1 if it is not + .prepend(ToggleOptionalByteArrayMutator::new(1)) + // Finally, a custom mutator that toggles the boolean part of the input + .prepend(ToggleBooleanMutator); + + // Scheduling layer for the mutations + let mutator_scheduler = StdScheduledMutator::new(mutators); + // Defining the mutator stage + let mut stages = tuple_list!(StdMutationalStage::new(mutator_scheduler)); + + // Run the fuzzer + fuzzer + .fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) + .expect("Error in the fuzzing loop"); +} diff --git a/fuzzers/baby/baby_fuzzer_multi/src/main.rs b/fuzzers/baby/baby_fuzzer_multi/src/main.rs index 6e7d9ae14d..dbcf35638a 100644 --- a/fuzzers/baby/baby_fuzzer_multi/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_multi/src/main.rs @@ -14,7 +14,7 @@ use libafl::{ feedbacks::{CrashFeedback, MaxMapFeedback, MinMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes, MultipartInput}, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs b/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs index dd8b47e642..471d6fee31 100644 --- a/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_swap_differential/src/main.rs @@ -17,7 +17,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/baby_fuzzer_with_forkexecutor/src/main.rs b/fuzzers/baby/baby_fuzzer_with_forkexecutor/src/main.rs index 7ab274bdcf..962f3e0d04 100644 --- a/fuzzers/baby/baby_fuzzer_with_forkexecutor/src/main.rs +++ b/fuzzers/baby/baby_fuzzer_with_forkexecutor/src/main.rs @@ -11,7 +11,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/baby_no_std/src/main.rs b/fuzzers/baby/baby_no_std/src/main.rs index 826fc7b90d..febcac17ff 100644 --- a/fuzzers/baby/baby_no_std/src/main.rs +++ b/fuzzers/baby/baby_no_std/src/main.rs @@ -19,7 +19,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs index 78cb2c7a2e..ca1d87f5d1 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs @@ -10,7 +10,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{BacktraceObserver, ConstMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs index 3dbe6f0ad0..9dbdb61dc9 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs @@ -10,7 +10,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{BacktraceObserver, ConstMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs index f4cb471658..65a3e282fe 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/command_executor/src/main.rs @@ -17,7 +17,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{get_asan_runtime_flags, AsanBacktraceObserver, StdMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs index 86fc4b41e9..e0322e930a 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/forkserver_executor/src/main.rs @@ -10,7 +10,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::BytesInput, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{AsanBacktraceObserver, ConstMapObserver, HitcountsMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs index 1b6e2507cc..c88ca60952 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{BacktraceObserver, StdMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs index a58ef4ec6d..ed7ffe4e5d 100644 --- a/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/baby/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{BacktraceObserver, StdMapObserver}, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs index 5b131120ca..4e4deb0680 100644 --- a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs +++ b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs @@ -11,7 +11,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::SimpleMonitor, - mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, + mutators::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, diff --git a/fuzzers/forkserver/forkserver_simple/src/main.rs b/fuzzers/forkserver/forkserver_simple/src/main.rs index 84a34f5402..c026197738 100644 --- a/fuzzers/forkserver/forkserver_simple/src/main.rs +++ b/fuzzers/forkserver/forkserver_simple/src/main.rs @@ -11,7 +11,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::SimpleMonitor, - mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, + mutators::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, diff --git a/fuzzers/frida/frida_executable_libpng/src/fuzzer.rs b/fuzzers/frida/frida_executable_libpng/src/fuzzer.rs index 0cb1d15ba3..7f55dbb62b 100644 --- a/fuzzers/frida/frida_executable_libpng/src/fuzzer.rs +++ b/fuzzers/frida/frida_executable_libpng/src/fuzzer.rs @@ -13,7 +13,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/frida/frida_gdiplus/src/fuzzer.rs b/fuzzers/frida/frida_gdiplus/src/fuzzer.rs index 8f9fdbe8de..1a8def4fc6 100644 --- a/fuzzers/frida/frida_gdiplus/src/fuzzer.rs +++ b/fuzzers/frida/frida_gdiplus/src/fuzzer.rs @@ -30,7 +30,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/frida/frida_libpng/src/fuzzer.rs b/fuzzers/frida/frida_libpng/src/fuzzer.rs index 63c8453767..440f03c62f 100644 --- a/fuzzers/frida/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida/frida_libpng/src/fuzzer.rs @@ -13,7 +13,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/fuzzbench/fuzzbench/src/lib.rs b/fuzzers/fuzzbench/fuzzbench/src/lib.rs index cf09c342e5..b282d84ab4 100644 --- a/fuzzers/fuzzbench/fuzzbench/src/lib.rs +++ b/fuzzers/fuzzbench/fuzzbench/src/lib.rs @@ -25,8 +25,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ diff --git a/fuzzers/fuzzbench/fuzzbench_ctx/src/lib.rs b/fuzzers/fuzzbench/fuzzbench_ctx/src/lib.rs index 531f40df20..52fd37ea59 100644 --- a/fuzzers/fuzzbench/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/fuzzbench/fuzzbench_ctx/src/lib.rs @@ -28,8 +28,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ diff --git a/fuzzers/fuzzbench/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench/fuzzbench_fork_qemu/src/fuzzer.rs index ee259748d7..12cfae19f4 100644 --- a/fuzzers/fuzzbench/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench/fuzzbench_fork_qemu/src/fuzzer.rs @@ -23,8 +23,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver}, schedulers::{ diff --git a/fuzzers/fuzzbench/fuzzbench_forkserver/src/main.rs b/fuzzers/fuzzbench/fuzzbench_forkserver/src/main.rs index c5185f62de..68b21d2a53 100644 --- a/fuzzers/fuzzbench/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/fuzzbench/fuzzbench_forkserver/src/main.rs @@ -18,8 +18,8 @@ use libafl::{ inputs::BytesInput, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{ CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver, diff --git a/fuzzers/fuzzbench/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/fuzzbench/fuzzbench_forkserver_cmplog/src/main.rs index 52c1cafbad..560ab516ff 100644 --- a/fuzzers/fuzzbench/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/fuzzbench/fuzzbench_forkserver_cmplog/src/main.rs @@ -18,8 +18,7 @@ use libafl::{ inputs::BytesInput, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, - StdMOptMutator, Tokens, + havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, StdMOptMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ diff --git a/fuzzers/fuzzbench/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench/fuzzbench_qemu/src/fuzzer.rs index 1897d52ef2..919d9c8111 100644 --- a/fuzzers/fuzzbench/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench/fuzzbench_qemu/src/fuzzer.rs @@ -22,8 +22,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{ diff --git a/fuzzers/fuzzbench/fuzzbench_text/src/lib.rs b/fuzzers/fuzzbench/fuzzbench_text/src/lib.rs index a0230ddaf8..d97d96bb0c 100644 --- a/fuzzers/fuzzbench/fuzzbench_text/src/lib.rs +++ b/fuzzers/fuzzbench/fuzzbench_text/src/lib.rs @@ -30,7 +30,7 @@ use libafl::{ GrimoireExtensionMutator, GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator, GrimoireStringReplacementMutator, }, - scheduled::havoc_mutations, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, diff --git a/fuzzers/libpng/libfuzzer_libpng/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng/src/lib.rs index 4ed929bc1f..9af9b9cbe9 100644 --- a/fuzzers/libpng/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng/src/lib.rs @@ -15,7 +15,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_accounting/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_accounting/src/lib.rs index c52cfd68a8..60a5f7c514 100644 --- a/fuzzers/libpng/libfuzzer_libpng_accounting/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_accounting/src/lib.rs @@ -16,7 +16,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_centralized/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_centralized/src/lib.rs index b1b5d681c4..ae7da19c3a 100644 --- a/fuzzers/libpng/libfuzzer_libpng_centralized/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_centralized/src/lib.rs @@ -16,7 +16,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_cmin/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_cmin/src/lib.rs index 4c568654fe..865097fe74 100644 --- a/fuzzers/libpng/libfuzzer_libpng_cmin/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_cmin/src/lib.rs @@ -18,7 +18,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_launcher/src/lib.rs index 870fc02e9a..6d626124e4 100644 --- a/fuzzers/libpng/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_launcher/src/lib.rs @@ -16,7 +16,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::{MultiMonitor, OnDiskTomlMonitor}, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_norestart/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_norestart/src/lib.rs index 9c4d7ebf94..79f9e22ade 100644 --- a/fuzzers/libpng/libfuzzer_libpng_norestart/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_norestart/src/lib.rs @@ -20,7 +20,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::{MultiMonitor, OnDiskTomlMonitor}, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, diff --git a/fuzzers/libpng/libfuzzer_libpng_tcp_manager/src/lib.rs b/fuzzers/libpng/libfuzzer_libpng_tcp_manager/src/lib.rs index 5484bce799..c390a4174b 100644 --- a/fuzzers/libpng/libfuzzer_libpng_tcp_manager/src/lib.rs +++ b/fuzzers/libpng/libfuzzer_libpng_tcp_manager/src/lib.rs @@ -15,7 +15,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/others/dynamic_analysis/src/lib.rs b/fuzzers/others/dynamic_analysis/src/lib.rs index f8503ce4a1..560ff377c0 100644 --- a/fuzzers/others/dynamic_analysis/src/lib.rs +++ b/fuzzers/others/dynamic_analysis/src/lib.rs @@ -24,8 +24,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, ProfilingObserver, TimeObserver}, schedulers::{ diff --git a/fuzzers/others/libafl-fuzz/src/fuzzer.rs b/fuzzers/others/libafl-fuzz/src/fuzzer.rs index fd1c745838..516ca4af11 100644 --- a/fuzzers/others/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/others/libafl-fuzz/src/fuzzer.rs @@ -11,9 +11,7 @@ use libafl::{ feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::StdFuzzer, inputs::BytesInput, - mutators::{ - scheduled::havoc_mutations, tokens_mutations, AFLppRedQueen, StdScheduledMutator, Tokens, - }, + mutators::{havoc_mutations, tokens_mutations, AFLppRedQueen, StdScheduledMutator, Tokens}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::{BaseSchedule, PowerSchedule}, diff --git a/fuzzers/others/libafl_atheris/src/lib.rs b/fuzzers/others/libafl_atheris/src/lib.rs index d6e4ee2a1b..da8b1d03fd 100644 --- a/fuzzers/others/libafl_atheris/src/lib.rs +++ b/fuzzers/others/libafl_atheris/src/lib.rs @@ -22,7 +22,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/others/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/others/libfuzzer_libmozjpeg/src/lib.rs index 6f40917791..ab029f1c34 100644 --- a/fuzzers/others/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/others/libfuzzer_libmozjpeg/src/lib.rs @@ -16,7 +16,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::StdMapObserver, diff --git a/fuzzers/others/libfuzzer_windows_asan/src/lib.rs b/fuzzers/others/libfuzzer_windows_asan/src/lib.rs index 0fedb32152..5b9a8aed4d 100644 --- a/fuzzers/others/libfuzzer_windows_asan/src/lib.rs +++ b/fuzzers/others/libfuzzer_windows_asan/src/lib.rs @@ -10,7 +10,10 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, - mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + mutators::{ + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, + }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, diff --git a/fuzzers/others/push_harness/src/main.rs b/fuzzers/others/push_harness/src/main.rs index 981a81ec5b..2614bad70f 100644 --- a/fuzzers/others/push_harness/src/main.rs +++ b/fuzzers/others/push_harness/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::QueueScheduler, stages::mutational::StdMutationalStage, diff --git a/fuzzers/others/push_stage_harness/src/main.rs b/fuzzers/others/push_stage_harness/src/main.rs index 27c78c26ef..4e90ac6b03 100644 --- a/fuzzers/others/push_stage_harness/src/main.rs +++ b/fuzzers/others/push_stage_harness/src/main.rs @@ -15,7 +15,7 @@ use libafl::{ fuzzer::StdFuzzer, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::StdMapObserver, schedulers::{QueueScheduler, Scheduler}, stages::push::{PushStageSharedState, StdMutationalPushStage}, diff --git a/fuzzers/others/sqlite_centralized_multi_machine/src/lib.rs b/fuzzers/others/sqlite_centralized_multi_machine/src/lib.rs index ececbea5e6..f2d37be2ee 100644 --- a/fuzzers/others/sqlite_centralized_multi_machine/src/lib.rs +++ b/fuzzers/others/sqlite_centralized_multi_machine/src/lib.rs @@ -19,7 +19,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver}, diff --git a/fuzzers/qemu/qemu_launcher/src/instance.rs b/fuzzers/qemu/qemu_launcher/src/instance.rs index 9c59d194fb..dd12e2d023 100644 --- a/fuzzers/qemu/qemu_launcher/src/instance.rs +++ b/fuzzers/qemu/qemu_launcher/src/instance.rs @@ -15,8 +15,8 @@ use libafl::{ inputs::BytesInput, monitors::Monitor, mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, StdScheduledMutator, Tokens, + havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, + StdScheduledMutator, Tokens, }, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{ diff --git a/fuzzers/qemu/qemu_systemmode/src/fuzzer_breakpoint.rs b/fuzzers/qemu/qemu_systemmode/src/fuzzer_breakpoint.rs index 0ac65bec52..326ff5e4a6 100644 --- a/fuzzers/qemu/qemu_systemmode/src/fuzzer_breakpoint.rs +++ b/fuzzers/qemu/qemu_systemmode/src/fuzzer_breakpoint.rs @@ -12,7 +12,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::MultiMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{CalibrationStage, StdMutationalStage}, diff --git a/fuzzers/qemu/qemu_systemmode/src/fuzzer_classic.rs b/fuzzers/qemu/qemu_systemmode/src/fuzzer_classic.rs index 6b78864b1a..85871387ec 100644 --- a/fuzzers/qemu/qemu_systemmode/src/fuzzer_classic.rs +++ b/fuzzers/qemu/qemu_systemmode/src/fuzzer_classic.rs @@ -12,7 +12,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::StdMutationalStage, diff --git a/fuzzers/qemu/qemu_systemmode/src/fuzzer_sync_exit.rs b/fuzzers/qemu/qemu_systemmode/src/fuzzer_sync_exit.rs index f9dad9cbb1..57b443ea67 100644 --- a/fuzzers/qemu/qemu_systemmode/src/fuzzer_sync_exit.rs +++ b/fuzzers/qemu/qemu_systemmode/src/fuzzer_sync_exit.rs @@ -11,7 +11,7 @@ use libafl::{ fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::MultiMonitor, - mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{CalibrationStage, StdMutationalStage}, diff --git a/fuzzers/stb/libfuzzer_stb_image/src/main.rs b/fuzzers/stb/libfuzzer_stb_image/src/main.rs index c59fa70cf7..964d2b26c5 100644 --- a/fuzzers/stb/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/stb/libfuzzer_stb_image/src/main.rs @@ -16,7 +16,7 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator, token_mutations::I2SRandReplace, }, observers::{CanTrack, TimeObserver}, diff --git a/fuzzers/stb/libfuzzer_stb_image_concolic/fuzzer/src/main.rs b/fuzzers/stb/libfuzzer_stb_image_concolic/fuzzer/src/main.rs index cbe6e1d7fd..611b4cb05e 100644 --- a/fuzzers/stb/libfuzzer_stb_image_concolic/fuzzer/src/main.rs +++ b/fuzzers/stb/libfuzzer_stb_image_concolic/fuzzer/src/main.rs @@ -20,7 +20,7 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes, Input}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator, token_mutations::I2SRandReplace, }, observers::{ diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index c86f811135..53b6dea0e1 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -11,7 +11,7 @@ use libafl_bolts::{ HasLen, }; -use crate::inputs::HasMutatorBytes; +use crate::inputs::{HasMutatorBytes, MappedInput}; /// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on /// inputs implementing the [`HasMutatorBytes`] for a sub-range of this input. @@ -202,6 +202,10 @@ where } } +impl<'a, I> MappedInput for BytesSubInput<'a, I> { + type Type<'b> = BytesSubInput<'b, I> where Self: 'b; +} + #[cfg(test)] mod tests { diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 75bba866bc..85bc929b69 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -195,6 +195,24 @@ pub trait HasMutatorBytes: HasLen { } } +/// Mapping types to themselves, used to ensure lifetime consistency for mapped mutators. +/// +/// Specifically, this is for [`Input`] types that are owned wrappers around a reference. The lifetime of the associated type should be the same as the reference. +pub trait MappedInput { + /// The type for which this trait is implemented + type Type<'a> + where + Self: 'a; +} + +impl MappedInput for Option +where + T: MappedInput, +{ + type Type<'a> = Option> + where T: 'a; +} + /// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`]. #[derive(Debug)] pub struct MutVecInput<'a>(&'a mut Vec); @@ -244,6 +262,10 @@ impl<'a> HasMutatorBytes for MutVecInput<'a> { } } +impl<'a> MappedInput for MutVecInput<'a> { + type Type<'b> = MutVecInput<'b> where Self: 'b; +} + /// Defines the input type shared across traits of the type. /// Needed for consistency across HasCorpus/HasSolutions and friends. pub trait UsesInput { diff --git a/libafl/src/mutators/havoc_mutations.rs b/libafl/src/mutators/havoc_mutations.rs new file mode 100644 index 0000000000..999794c9c9 --- /dev/null +++ b/libafl/src/mutators/havoc_mutations.rs @@ -0,0 +1,272 @@ +//! [`crate::mutators::Mutator`] collection equivalent to AFL++'s havoc mutations + +use libafl_bolts::tuples::{Map, Merge}; +use tuple_list::{tuple_list, tuple_list_type}; + +use crate::mutators::{ + mapping::{ + MappedInputFunctionMappingMutator, OptionMappingMutator, + ToMappedInputFunctionMappingMutatorMapper, ToOptionMappingMutatorMapper, + }, + mutations::{ + BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator, + ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator, + BytesDeleteMutator, BytesExpandMutator, BytesInsertCopyMutator, BytesInsertMutator, + BytesRandInsertMutator, BytesRandSetMutator, BytesSetMutator, BytesSwapMutator, + CrossoverInsertMutator, CrossoverReplaceMutator, DwordAddMutator, DwordInterestingMutator, + MappedCrossoverInsertMutator, MappedCrossoverReplaceMutator, QwordAddMutator, + WordAddMutator, WordInterestingMutator, + }, +}; + +/// Tuple type of the mutations that compose the Havoc mutator without crossover mutations +pub type HavocMutationsNoCrossoverType = 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, +); + +/// Tuple type of the mutations that compose the Havoc mutator's crossover mutations +pub type HavocCrossoverType = + tuple_list_type!(CrossoverInsertMutator, CrossoverReplaceMutator); + +/// Tuple type of the mutations that compose the Havoc mutator's crossover mutations for mapped input types +pub type MappedHavocCrossoverType = tuple_list_type!( + MappedCrossoverInsertMutator, + MappedCrossoverReplaceMutator, +); + +/// 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, +); + +/// Tuple type of the mutations that compose the Havoc mutator for mapped input types +pub type MappedHavocMutationsType = tuple_list_type!( + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, +); + +/// Tuple type of the mutations that compose the Havoc mutator for mapped input types, for optional byte array input parts +pub type OptionMappedHavocMutationsType = tuple_list_type!( + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator, F1, II>, + MappedInputFunctionMappingMutator< + OptionMappingMutator>, + F1, + II, + >, + MappedInputFunctionMappingMutator< + OptionMappingMutator>, + F1, + II, + >, +); + +/// Get the mutations that compose the Havoc mutator (only applied to single inputs) +#[must_use] +pub fn havoc_mutations_no_crossover() -> HavocMutationsNoCrossoverType { + 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(), + ) +} + +/// Get the mutations that compose the Havoc mutator's crossover strategy +#[must_use] +pub fn havoc_crossover() -> HavocCrossoverType { + tuple_list!( + CrossoverInsertMutator::new(), + CrossoverReplaceMutator::new(), + ) +} + +/// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic +pub fn havoc_crossover_with_corpus_mapper(input_mapper: F) -> MappedHavocCrossoverType +where + F: Clone, +{ + tuple_list!( + MappedCrossoverInsertMutator::new(input_mapper.clone()), + MappedCrossoverReplaceMutator::new(input_mapper.clone()), + ) +} + +/// Get the mutations that compose the Havoc mutator's crossover strategy with custom corpus extraction logic +pub fn havoc_crossover_with_corpus_mapper_optional( + input_mapper: F, +) -> MappedHavocCrossoverType +where + F: Clone, +{ + tuple_list!( + MappedCrossoverInsertMutator::new(input_mapper.clone()), + MappedCrossoverReplaceMutator::new(input_mapper.clone()), + ) +} + +/// Get the mutations that compose the Havoc mutator +#[must_use] +pub fn havoc_mutations() -> HavocMutationsType { + havoc_mutations_no_crossover().merge(havoc_crossover()) +} + +/// Get the mutations that compose the Havoc mutator for mapped input types +/// +/// Check the example fuzzer for details on how to use this. +#[must_use] +pub fn mapped_havoc_mutations( + current_input_mapper: F1, + input_from_corpus_mapper: F2, +) -> MappedHavocMutationsType +where + F1: Clone + FnMut(IO1) -> II, + F2: Clone + Fn(IO2) -> O, +{ + havoc_mutations_no_crossover() + .merge(havoc_crossover_with_corpus_mapper(input_from_corpus_mapper)) + .map(ToMappedInputFunctionMappingMutatorMapper::new( + current_input_mapper, + )) +} + +/// Get the mutations that compose the Havoc mutator for mapped input types, for optional input parts +/// +/// Check the example fuzzer for details on how to use this. +#[must_use] +pub fn optional_mapped_havoc_mutations( + current_input_mapper: F1, + input_from_corpus_mapper: F2, +) -> OptionMappedHavocMutationsType +where + F1: Clone + FnMut(IO1) -> II, + F2: Clone + Fn(IO2) -> O, +{ + havoc_mutations_no_crossover() + .merge(havoc_crossover_with_corpus_mapper_optional( + input_from_corpus_mapper, + )) + .map(ToOptionMappingMutatorMapper) + .map(ToMappedInputFunctionMappingMutatorMapper::new( + current_input_mapper, + )) +} diff --git a/libafl/src/mutators/mapping.rs b/libafl/src/mutators/mapping.rs new file mode 100644 index 0000000000..27dc7990d5 --- /dev/null +++ b/libafl/src/mutators/mapping.rs @@ -0,0 +1,414 @@ +//! Allowing mixing and matching between [`Mutator`] and [`crate::inputs::Input`] types. +use alloc::borrow::Cow; +use core::marker::PhantomData; + +use libafl_bolts::{tuples::MappingFunctor, Named}; + +use crate::{ + inputs::MappedInput, + mutators::{MutationResult, Mutator}, + Error, +}; + +/// Mapping [`Mutator`] using a function returning a reference. +/// +/// Allows using [`Mutator`]s for a certain type on (parts of) other input types that can be mapped to this type. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use std::vec::Vec; +/// +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ +/// ByteIncMutator, FunctionMappingMutator, MappedInputFunctionMappingMutator, +/// MutationResult, Mutator, +/// }, +/// state::NopState, +/// }; +/// +/// type CustomInput = (Vec,); +/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec { +/// &mut input.0 +/// } +/// +/// fn extract_from_ref(input: &mut Vec) -> MutVecInput<'_> { +/// input.into() +/// } +/// +/// // construct a mapper that works on &mut Vec +/// let inner: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> = +/// MappedInputFunctionMappingMutator::new(extract_from_ref, ByteIncMutator::new()); +/// let mut outer = FunctionMappingMutator::new(extract_to_ref, inner); +/// +/// let mut input: CustomInput = (vec![1],); +/// +/// let mut state: NopState = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input, (vec![2],)); +/// ``` +#[derive(Debug)] +pub struct FunctionMappingMutator { + mapper: F, + inner: M, + name: Cow<'static, str>, +} + +impl FunctionMappingMutator { + /// Creates a new [`FunctionMappingMutator`] + pub fn new(mapper: F, inner: M) -> Self + where + M: Named, + { + let name = Cow::Owned(format!("FunctionMappingMutator<{}>", inner.name())); + Self { + mapper, + inner, + name, + } + } +} + +impl Mutator for FunctionMappingMutator +where + F: for<'a> FnMut(&'a mut IO) -> &'a mut II, + M: Mutator, +{ + fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result { + self.inner.mutate(state, (self.mapper)(input)) + } +} + +impl Named for FunctionMappingMutator { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`ToFunctionMappingMutatorMapper`]s. +/// +/// See the explanation of [`ToFunctionMappingMutatorMapper`] for details. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use std::vec::Vec; +/// +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ +/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator, +/// ToFunctionMappingMutatorMapper, +/// }, +/// state::NopState, +/// }; +/// +/// use libafl_bolts::tuples::{tuple_list, Map}; +/// +/// type CustomInput = (Vec,); +/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec { +/// &mut input.0 +/// } +/// +/// fn extract_from_ref(input: &mut Vec) -> MutVecInput<'_> { +/// input.into() +/// } +/// +/// // construct a mapper that works on &mut Vec +/// let inner: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> = +/// MappedInputFunctionMappingMutator::new(extract_from_ref, ByteIncMutator::new()); +/// let inner_list = tuple_list!(inner); +/// let outer_list = inner_list.map(ToFunctionMappingMutatorMapper::new(extract_to_ref)); +/// let mut outer = outer_list.0; +/// +/// let mut input: CustomInput = (vec![1],); +/// +/// let mut state: NopState = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input, (vec![2],)); +/// ``` +#[derive(Debug)] +pub struct ToFunctionMappingMutatorMapper { + mapper: F, +} + +impl ToFunctionMappingMutatorMapper { + /// Creates a new [`ToFunctionMappingMutatorMapper`] + pub fn new(mapper: F) -> Self { + Self { mapper } + } +} + +impl MappingFunctor for ToFunctionMappingMutatorMapper +where + F: Clone, + M: Named, +{ + type Output = FunctionMappingMutator; + + fn apply(&mut self, from: M) -> Self::Output { + FunctionMappingMutator::new(self.mapper.clone(), from) + } +} + +/// Mapping [`Mutator`] using a function returning a wrapped reference (see [`MappedInput`]). +/// +/// Allows using [`Mutator`]s for a certain type on (parts of) other input types that can be mapped to this type. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use std::vec::Vec; +/// +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ +/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator, +/// }, +/// state::NopState, +/// }; +/// +/// type CustomInput = (Vec,); +/// fn extract(input: &mut CustomInput) -> MutVecInput<'_> { +/// (&mut input.0).into() +/// } +/// +/// let inner = ByteIncMutator::new(); +/// let mut outer: MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>> = +/// MappedInputFunctionMappingMutator::new(extract, inner); +/// +/// let mut input: CustomInput = (vec![1],); +/// +/// let mut state: NopState = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input, (vec![2],)); +/// ``` +#[derive(Debug)] +pub struct MappedInputFunctionMappingMutator { + mapper: F, + inner: M, + name: Cow<'static, str>, + phantom: PhantomData, +} + +impl MappedInputFunctionMappingMutator { + /// Creates a new [`MappedInputFunctionMappingMutator`] + pub fn new(mapper: F, inner: M) -> Self + where + M: Named, + { + let name = Cow::Owned(format!( + "MappedInputFunctionMappingMutator<{}>", + inner.name() + )); + + Self { + mapper, + inner, + name, + phantom: PhantomData, + } + } +} + +impl Mutator for MappedInputFunctionMappingMutator +where + for<'a> M: Mutator, S>, + for<'a> II: MappedInput + 'a, + for<'a> F: FnMut(&'a mut IO) -> II::Type<'a>, +{ + fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result { + let mapped = &mut (self.mapper)(input); + self.inner.mutate(state, mapped) + } +} + +impl Named for MappedInputFunctionMappingMutator { + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`MappedInputFunctionMappingMutator`]s. +/// +/// See the explanation of [`MappedInputFunctionMappingMutator`] for details. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use std::vec::Vec; +/// +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ +/// ByteIncMutator, MappedInputFunctionMappingMutator, MutationResult, Mutator, +/// ToMappedInputFunctionMappingMutatorMapper, +/// }, +/// state::NopState, +/// }; +/// +/// use libafl_bolts::tuples::{tuple_list, Map}; +/// +/// type CustomInput = (Vec,); +/// fn extract(input: &mut CustomInput) -> MutVecInput<'_> { +/// (&mut input.0).into() +/// } +/// +/// let inner = tuple_list!(ByteIncMutator::new()); +/// let outer_list: (MappedInputFunctionMappingMutator<_, _, MutVecInput<'_>>, _) = +/// inner.map(ToMappedInputFunctionMappingMutatorMapper::new(extract)); +/// let mut outer = outer_list.0; +/// +/// let mut input: CustomInput = (vec![1],); +/// +/// let mut state: NopState = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input, (vec![2],)); +/// ``` +#[derive(Debug)] +pub struct ToMappedInputFunctionMappingMutatorMapper { + mapper: F, + phantom: PhantomData, +} + +impl ToMappedInputFunctionMappingMutatorMapper { + /// Creates a new [`ToMappedInputFunctionMappingMutatorMapper`] + pub fn new(mapper: F) -> Self + where + F: FnMut(IO) -> II, + { + Self { + mapper, + phantom: PhantomData, + } + } +} + +impl MappingFunctor for ToMappedInputFunctionMappingMutatorMapper +where + F: Clone, + M: Named, +{ + type Output = MappedInputFunctionMappingMutator; + + fn apply(&mut self, from: M) -> Self::Output { + MappedInputFunctionMappingMutator::new(self.mapper.clone(), from) + } +} + +/// Mapping [`Mutator`] for dealing with input parts wrapped in [`Option`]. +/// +/// Allows using [`Mutator`]s for a certain type on (parts of) other input types that can be mapped to an [`Option`] of said type. +/// +/// Returns [`MutationResult::Skipped`] if the mapper returns [`None`]. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ByteIncMutator, MutationResult, Mutator, OptionMappingMutator}, +/// state::NopState, +/// }; +/// +/// let inner = ByteIncMutator::new(); +/// let mut outer = OptionMappingMutator::new(inner); +/// +/// let mut input_raw = vec![1]; +/// let input: MutVecInput = (&mut input_raw).into(); +/// let mut input_wrapped = Some(input); +/// let mut state: NopState> = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input_wrapped).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input_raw, vec![2]); +/// +/// let mut empty_input: Option = None; +/// let res2 = outer.mutate(&mut state, &mut empty_input).unwrap(); +/// assert_eq!(res2, MutationResult::Skipped); +/// ``` +#[derive(Debug)] +pub struct OptionMappingMutator { + inner: M, + name: Cow<'static, str>, +} + +impl OptionMappingMutator { + /// Creates a new [`OptionMappingMutator`] + pub fn new(inner: M) -> Self + where + M: Named, + { + let name = Cow::Owned(format!("OptionMappingMutator<{}>", inner.name())); + Self { inner, name } + } +} + +impl Mutator, S> for OptionMappingMutator +where + M: Mutator, +{ + fn mutate(&mut self, state: &mut S, input: &mut Option) -> Result { + match input { + None => Ok(MutationResult::Skipped), + Some(i) => self.inner.mutate(state, i), + } + } +} + +impl Named for OptionMappingMutator +where + M: Named, +{ + fn name(&self) -> &Cow<'static, str> { + &self.name + } +} + +/// Mapper to use to map a [`tuple_list`] of [`Mutator`]s using [`OptionMappingMutator`]s. +/// +/// See the explanation of [`OptionMappingMutator`] for details. +/// +/// # Example +#[cfg_attr(feature = "std", doc = " ```")] +#[cfg_attr(not(feature = "std"), doc = " ```ignore")] +/// use libafl::{ +/// inputs::MutVecInput, +/// mutators::{ByteIncMutator, MutationResult, Mutator, ToOptionMappingMutatorMapper}, +/// state::NopState, +/// }; +/// use libafl_bolts::tuples::{tuple_list, Map}; +/// +/// let inner = tuple_list!(ByteIncMutator::new()); +/// let outer_list = inner.map(ToOptionMappingMutatorMapper); +/// let mut outer = outer_list.0; +/// +/// let mut input_raw = vec![1]; +/// let input: MutVecInput = (&mut input_raw).into(); +/// let mut input_wrapped = Some(input); +/// let mut state: NopState> = NopState::new(); +/// let res = outer.mutate(&mut state, &mut input_wrapped).unwrap(); +/// assert_eq!(res, MutationResult::Mutated); +/// assert_eq!(input_raw, vec![2]); +/// +/// let mut empty_input: Option = None; +/// let res2 = outer.mutate(&mut state, &mut empty_input).unwrap(); +/// assert_eq!(res2, MutationResult::Skipped); +/// ``` +#[derive(Debug)] +pub struct ToOptionMappingMutatorMapper; + +impl MappingFunctor for ToOptionMappingMutatorMapper +where + M: Named, +{ + type Output = OptionMappingMutator; + + fn apply(&mut self, from: M) -> Self::Output { + OptionMappingMutator::new(from) + } +} diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index c0e7e9563e..ffe736c5f0 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -11,6 +11,8 @@ pub use mutations::*; pub mod token_mutations; use serde::{Deserialize, Serialize}; pub use token_mutations::*; +pub mod havoc_mutations; +pub use havoc_mutations::*; pub mod encoded_mutations; pub use encoded_mutations::*; pub mod mopt_mutator; @@ -19,6 +21,8 @@ pub mod gramatron; pub use gramatron::*; pub mod grimoire; pub use grimoire::*; +pub mod mapping; +pub use mapping::*; pub mod tuneable; pub use tuneable::*; diff --git a/libafl/src/mutators/multi.rs b/libafl/src/mutators/multi.rs index a4263951ba..fa3405703f 100644 --- a/libafl/src/mutators/multi.rs +++ b/libafl/src/mutators/multi.rs @@ -167,7 +167,13 @@ where } }; - return Ok(Self::crossover_insert(part, size, target, range, chosen)); + return Ok(Self::crossover_insert( + part, + size, + target, + range, + chosen.bytes(), + )); } return Ok(MutationResult::Skipped); @@ -207,7 +213,7 @@ where size, target, range, - &other.parts()[choice], + other.parts()[choice].bytes(), )) } else { // just add it! @@ -271,7 +277,7 @@ where } }; - return Ok(Self::crossover_replace(part, target, range, chosen)); + return Ok(Self::crossover_replace(part, target, range, chosen.bytes())); } return Ok(MutationResult::Skipped); @@ -310,7 +316,7 @@ where part, target, range, - &other.parts()[choice], + other.parts()[choice].bytes(), )) } else { // just add it! diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 6351ec05df..93e9d09920 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -10,7 +10,7 @@ use libafl_bolts::{rands::Rand, Named}; use crate::{ corpus::Corpus, - inputs::HasMutatorBytes, + inputs::{HasMutatorBytes, UsesInput}, mutators::{MutationResult, Mutator}, random_corpus_id_with_disabled, state::{HasCorpus, HasMaxSize, HasRand}, @@ -1030,12 +1030,12 @@ pub struct CrossoverInsertMutator { } impl CrossoverInsertMutator { - pub(crate) fn crossover_insert( + pub(crate) fn crossover_insert( input: &mut I, size: usize, target: usize, range: Range, - other: &I2, + other: &[u8], ) -> MutationResult { input.resize(size + range.len(), 0); unsafe { @@ -1048,13 +1048,7 @@ impl CrossoverInsertMutator { } unsafe { - buffer_copy( - input.bytes_mut(), - other.bytes(), - range.start, - target, - range.len(), - ); + buffer_copy(input.bytes_mut(), other, range.start, target, range.len()); } MutationResult::Mutated } @@ -1097,7 +1091,13 @@ where // No need to load the input again, it'll still be cached. let other = other_testcase.input().as_ref().unwrap(); - Ok(Self::crossover_insert(input, size, target, range, other)) + Ok(Self::crossover_insert( + input, + size, + target, + range, + other.bytes(), + )) } } @@ -1125,20 +1125,14 @@ pub struct CrossoverReplaceMutator { } impl CrossoverReplaceMutator { - pub(crate) fn crossover_replace( + pub(crate) fn crossover_replace( input: &mut I, target: usize, range: Range, - other: &I2, + other: &[u8], ) -> MutationResult { unsafe { - buffer_copy( - input.bytes_mut(), - other.bytes(), - range.start, - target, - range.len(), - ); + buffer_copy(input.bytes_mut(), other, range.start, target, range.len()); } MutationResult::Mutated } @@ -1180,7 +1174,7 @@ where // No need to load the input again, it'll still be cached. let other = other_testcase.input().as_ref().unwrap(); - Ok(Self::crossover_replace(input, target, range, other)) + Ok(Self::crossover_replace(input, target, range, other.bytes())) } } @@ -1201,6 +1195,194 @@ impl CrossoverReplaceMutator { } } +trait IntoOptionBytes { + type Type<'b>; + + fn into_option_bytes<'a>(self) -> Option<&'a [u8]> + where + Self: 'a; +} + +impl<'a> IntoOptionBytes for &'a [u8] { + type Type<'b> = &'b [u8]; + + fn into_option_bytes<'b>(self) -> Option<&'b [u8]> + where + Self: 'b, + { + Some(self) + } +} + +impl<'a> IntoOptionBytes for Option<&'a [u8]> { + type Type<'b> = Option<&'b [u8]>; + + fn into_option_bytes<'b>(self) -> Option<&'b [u8]> + where + Self: 'b, + { + self + } +} + +/// Crossover insert mutation for inputs mapped to a bytes vector +#[derive(Debug)] +pub struct MappedCrossoverInsertMutator { + input_mapper: F, + phantom: PhantomData, +} + +impl MappedCrossoverInsertMutator { + /// Creates a new [`MappedCrossoverInsertMutator`] + pub fn new(input_mapper: F) -> Self { + Self { + input_mapper, + phantom: PhantomData, + } + } +} + +impl Mutator for MappedCrossoverInsertMutator +where + S: HasCorpus + HasMaxSize + HasRand + UsesInput, + I: HasMutatorBytes, + for<'a> O: IntoOptionBytes, + for<'a> O::Type<'a>: IntoOptionBytes, + for<'a> F: Fn(&'a S::Input) -> ::Type<'a>, +{ + fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { + let size = input.bytes().len(); + let max_size = state.max_size(); + if size >= max_size { + return Ok(MutationResult::Skipped); + } + + let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut()); + // We don't want to use the testcase we're already using for splicing + if let Some(cur) = state.corpus().current() { + if id == *cur { + return Ok(MutationResult::Skipped); + } + } + + let other_size = { + let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); + let other_input = other_testcase.load_input(state.corpus())?; + let input_mapped = (self.input_mapper)(other_input).into_option_bytes(); + input_mapped.map_or(0, <[u8]>::len) + }; + + if other_size < 2 { + return Ok(MutationResult::Skipped); + } + + let range = rand_range(state, other_size, min(other_size, max_size - size)); + let target = state.rand_mut().below(size); // TODO: fix bug if size is 0 + + let other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); + // No need to load the input again, it'll still be cached. + let other_input = &mut other_testcase.input().as_ref().unwrap(); + let wrapped_mapped_other_input = (self.input_mapper)(other_input).into_option_bytes(); + if wrapped_mapped_other_input.is_none() { + return Ok(MutationResult::Skipped); + } + let mapped_other_input = wrapped_mapped_other_input.unwrap(); + + Ok(CrossoverInsertMutator::crossover_insert( + input, + size, + target, + range, + mapped_other_input, + )) + } +} + +impl Named for MappedCrossoverInsertMutator { + fn name(&self) -> &Cow<'static, str> { + static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverInsertMutator"); + &NAME + } +} + +/// Crossover replace mutation for inputs mapped to a bytes vector +#[derive(Debug)] +pub struct MappedCrossoverReplaceMutator { + input_mapper: F, + phantom: PhantomData, +} + +impl MappedCrossoverReplaceMutator { + /// Creates a new [`MappedCrossoverReplaceMutator`] + pub fn new(input_mapper: F) -> Self { + Self { + input_mapper, + phantom: PhantomData, + } + } +} + +impl Mutator for MappedCrossoverReplaceMutator +where + S: HasCorpus + HasMaxSize + HasRand + UsesInput, + I: HasMutatorBytes, + O: IntoOptionBytes, + for<'a> O::Type<'a>: IntoOptionBytes, + for<'a> F: Fn(&'a S::Input) -> ::Type<'a>, +{ + fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { + let size = input.bytes().len(); + if size == 0 { + return Ok(MutationResult::Skipped); + } + + let id = random_corpus_id_with_disabled!(state.corpus(), state.rand_mut()); + // We don't want to use the testcase we're already using for splicing + if let Some(cur) = state.corpus().current() { + if id == *cur { + return Ok(MutationResult::Skipped); + } + } + + let other_size = { + let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); + let other_input = other_testcase.load_input(state.corpus())?; + let input_mapped = (self.input_mapper)(other_input).into_option_bytes(); + input_mapped.map_or(0, <[u8]>::len) + }; + + if other_size < 2 { + return Ok(MutationResult::Skipped); + } + + let target = state.rand_mut().below(size); + let range = rand_range(state, other_size, min(other_size, size - target)); + + let other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); + // No need to load the input again, it'll still be cached. + let other_input = &mut other_testcase.input().as_ref().unwrap(); + let wrapped_mapped_other_input = (self.input_mapper)(other_input).into_option_bytes(); + if wrapped_mapped_other_input.is_none() { + return Ok(MutationResult::Skipped); + } + let mapped_other_input = wrapped_mapped_other_input.unwrap(); + + Ok(CrossoverReplaceMutator::crossover_replace( + input, + target, + range, + mapped_other_input, + )) + } +} + +impl Named for MappedCrossoverReplaceMutator { + fn name(&self) -> &Cow<'static, str> { + static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverReplaceMutator"); + &NAME + } +} + /// 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; diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 6b00b506be..850cfc959d 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -9,7 +9,7 @@ use core::{ use libafl_bolts::{ rands::Rand, - tuples::{tuple_list, tuple_list_type, Merge, NamedTuple}, + tuples::{tuple_list, tuple_list_type, NamedTuple}, Named, }; use serde::{Deserialize, Serialize}; @@ -18,14 +18,6 @@ use super::MutationId; use crate::{ corpus::{Corpus, CorpusId}, mutators::{ - mutations::{ - BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, ByteIncMutator, - ByteInterestingMutator, ByteNegMutator, ByteRandMutator, BytesCopyMutator, - BytesDeleteMutator, BytesExpandMutator, BytesInsertCopyMutator, BytesInsertMutator, - BytesRandInsertMutator, BytesRandSetMutator, BytesSetMutator, BytesSwapMutator, - CrossoverInsertMutator, CrossoverReplaceMutator, DwordAddMutator, - DwordInterestingMutator, QwordAddMutator, WordAddMutator, WordInterestingMutator, - }, token_mutations::{TokenInsert, TokenReplace}, MutationResult, Mutator, MutatorsTuple, }, @@ -221,117 +213,6 @@ where } } -/// Tuple type of the mutations that compose the Havoc mutator without crossover mutations -pub type HavocMutationsNoCrossoverType = 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, -); - -/// Tuple type of the mutations that compose the Havoc mutator's crossover mutations -pub type HavocCrossoverType = - tuple_list_type!(CrossoverInsertMutator, CrossoverReplaceMutator); - -/// 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 (only applied to single inputs) -#[must_use] -pub fn havoc_mutations_no_crossover() -> HavocMutationsNoCrossoverType { - 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(), - ) -} - -/// Get the mutations that compose the Havoc mutator's crossover strategy -#[must_use] -pub fn havoc_crossover() -> HavocCrossoverType { - tuple_list!( - CrossoverInsertMutator::new(), - CrossoverReplaceMutator::new(), - ) -} - -/// Get the mutations that compose the Havoc mutator -#[must_use] -pub fn havoc_mutations() -> HavocMutationsType { - havoc_mutations_no_crossover().merge(havoc_crossover()) -} - /// Get the mutations that uses the Tokens metadata #[must_use] pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) { @@ -482,9 +363,8 @@ mod tests { feedbacks::ConstFeedback, inputs::{BytesInput, HasMutatorBytes}, mutators::{ - mutations::SpliceMutator, - scheduled::{havoc_mutations, StdScheduledMutator}, - Mutator, + havoc_mutations::havoc_mutations, mutations::SpliceMutator, + scheduled::StdScheduledMutator, Mutator, }, state::StdState, }; diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index 8949af3588..6166ea5796 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -12,7 +12,8 @@ use libafl::{ generators::RandBytesGenerator, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index 8e4b6675d3..cd8728f8b3 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -15,7 +15,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 41ee724677..bcf7e5da57 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -17,7 +17,8 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::{ - scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + havoc_mutations::havoc_mutations, + scheduled::{tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, I2SRandReplace, },