Add MappedInputs to allow havoc muations for custom (sub-)inputs (#2422)

* introducing MappingMutator

* extending mapping mutators

* adding example fuzzer

* making crossover mutators more flexible.

* moving example fuzzer

* fixing dependency paths

* formatting

* fixing no std error

* fixing broken docs link

* fixing import paths

* fixing imports

* more format fixing

* adding new example fuzzer to CI

* fixing further imports

* fixing formatting

* formatting fixes

* improving docs for the example fuzzer

* adding documentation and tests to mapping mutators

* make extraction function for mapped crossover mutators more general

* adding MutVecFunctionMappingMutator

* Introducing WrapsReference

* code cleanup for mapping mutators

* adding tests and docs to mapping mutators

* reformatting comments

* fixing merging of mutators in example fuzzer

* formatting

* formatting v2

* cleanup according to PR comments

* adding type constraint to MappedInput helper functions to remove the need to specify types

* matching functions passed to mapped_havoc_mutations

* removing unnecessary constraints

* mapping mutators now contain the name of their inner mutator

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Valentin Huber 2024-09-18 23:23:04 +02:00 committed by GitHub
parent 5b7d307a6a
commit 2c676f0352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
60 changed files with 1391 additions and 206 deletions

View File

@ -254,6 +254,7 @@ jobs:
- ./fuzzers/baby/baby_fuzzer_grimoire - ./fuzzers/baby/baby_fuzzer_grimoire
- ./fuzzers/baby/baby_fuzzer_gramatron - ./fuzzers/baby/baby_fuzzer_gramatron
- ./fuzzers/baby/baby_fuzzer - ./fuzzers/baby/baby_fuzzer
- ./fuzzers/baby/baby_fuzzer_custom_input
- ./fuzzers/baby/baby_fuzzer_nautilus - ./fuzzers/baby/baby_fuzzer_nautilus
# - ./fuzzers/baby/backtrace_baby_fuzzers # - ./fuzzers/baby/backtrace_baby_fuzzers
- ./fuzzers/baby/baby_fuzzer_unicode - ./fuzzers/baby/baby_fuzzer_unicode

View File

@ -14,7 +14,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -0,0 +1,24 @@
[package]
name = "baby_fuzzer_custom_input"
version = "0.1.0"
authors = ["Valentin Huber <contact@valentinhuber.me>"]
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 = "*"

View File

@ -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`.

View File

@ -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<u8>,
pub optional_byte_array: Option<Vec<u8>>,
pub boolean: bool,
}
/// Hash-based implementation
impl Input for CustomInput {
fn generate_name(&self, _id: Option<CorpusId>) -> 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<MutVecInput<'_>> {
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<S> Generator<CustomInput, S> for CustomInputGenerator
where
S: HasRand,
{
fn generate(&mut self, state: &mut S) -> Result<CustomInput, Error> {
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<G> {
generator: G,
}
impl<S> ToggleOptionalByteArrayMutator<RandBytesGenerator<S>>
where
S: HasRand,
{
/// Creates a new [`ToggleOptionalByteArrayMutator`]
pub fn new(length: usize) -> Self {
Self {
generator: RandBytesGenerator::new(length),
}
}
}
impl<G, S> Mutator<CustomInput, S> for ToggleOptionalByteArrayMutator<G>
where
S: HasRand,
G: Generator<BytesInput, S>,
{
fn mutate(&mut self, state: &mut S, input: &mut CustomInput) -> Result<MutationResult, Error> {
input.optional_byte_array = match input.optional_byte_array {
None => Some(self.generator.generate(state)?.target_bytes().into()),
Some(_) => None,
};
Ok(MutationResult::Mutated)
}
}
impl<G> Named for ToggleOptionalByteArrayMutator<G> {
fn name(&self) -> &Cow<'static, str> {
&Cow::Borrowed("ToggleOptionalByteArrayMutator")
}
}
/// [`Mutator`] that toggles the boolean field in a [`CustomInput`]
pub struct ToggleBooleanMutator;
impl<S> Mutator<CustomInput, S> for ToggleBooleanMutator {
fn mutate(&mut self, _state: &mut S, input: &mut CustomInput) -> Result<MutationResult, Error> {
input.boolean = !input.boolean;
Ok(MutationResult::Mutated)
}
}
impl Named for ToggleBooleanMutator {
fn name(&self) -> &Cow<'static, str> {
&Cow::Borrowed("ToggleBooleanMutator")
}
}

View File

@ -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");
}

View File

@ -14,7 +14,7 @@ use libafl::{
feedbacks::{CrashFeedback, MaxMapFeedback, MinMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, MinMapFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes, MultipartInput}, inputs::{BytesInput, HasTargetBytes, MultipartInput},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -17,7 +17,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -11,7 +11,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -19,7 +19,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -10,7 +10,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{BacktraceObserver, ConstMapObserver}, observers::{BacktraceObserver, ConstMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -10,7 +10,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{BacktraceObserver, ConstMapObserver}, observers::{BacktraceObserver, ConstMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -17,7 +17,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{get_asan_runtime_flags, AsanBacktraceObserver, StdMapObserver}, observers::{get_asan_runtime_flags, AsanBacktraceObserver, StdMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -10,7 +10,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{AsanBacktraceObserver, ConstMapObserver, HitcountsMapObserver}, observers::{AsanBacktraceObserver, ConstMapObserver, HitcountsMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -12,7 +12,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{BacktraceObserver, StdMapObserver}, observers::{BacktraceObserver, StdMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -12,7 +12,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{BacktraceObserver, StdMapObserver}, observers::{BacktraceObserver, StdMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -11,7 +11,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, mutators::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -11,7 +11,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, mutators::{havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -13,7 +13,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -30,7 +30,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -13,7 +13,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -25,8 +25,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{

View File

@ -28,8 +28,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{

View File

@ -23,8 +23,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{

View File

@ -18,8 +18,8 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{ observers::{
CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver, CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver,

View File

@ -18,8 +18,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, StdMOptMutator, Tokens,
StdMOptMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{

View File

@ -22,8 +22,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{ schedulers::{

View File

@ -30,7 +30,7 @@ use libafl::{
GrimoireExtensionMutator, GrimoireRandomDeleteMutator, GrimoireExtensionMutator, GrimoireRandomDeleteMutator,
GrimoireRecursiveReplacementMutator, GrimoireStringReplacementMutator, GrimoireRecursiveReplacementMutator, GrimoireStringReplacementMutator,
}, },
scheduled::havoc_mutations, havoc_mutations,
token_mutations::I2SRandReplace, token_mutations::I2SRandReplace,
tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens,
}, },

View File

@ -15,7 +15,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -16,7 +16,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -16,7 +16,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},

View File

@ -18,7 +18,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},

View File

@ -16,7 +16,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::{MultiMonitor, OnDiskTomlMonitor}, monitors::{MultiMonitor, OnDiskTomlMonitor},
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},

View File

@ -20,7 +20,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::{MultiMonitor, OnDiskTomlMonitor}, monitors::{MultiMonitor, OnDiskTomlMonitor},
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},

View File

@ -15,7 +15,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -24,8 +24,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, ProfilingObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, ProfilingObserver, TimeObserver},
schedulers::{ schedulers::{

View File

@ -11,9 +11,7 @@ use libafl::{
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::StdFuzzer, fuzzer::StdFuzzer,
inputs::BytesInput, inputs::BytesInput,
mutators::{ mutators::{havoc_mutations, tokens_mutations, AFLppRedQueen, StdScheduledMutator, Tokens},
scheduled::havoc_mutations, tokens_mutations, AFLppRedQueen, StdScheduledMutator, Tokens,
},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::{BaseSchedule, PowerSchedule}, powersched::{BaseSchedule, PowerSchedule},

View File

@ -22,7 +22,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -16,7 +16,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::StdMapObserver, observers::StdMapObserver,

View File

@ -10,7 +10,10 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::{
havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
},
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,

View File

@ -12,7 +12,7 @@ use libafl::{
generators::RandPrintablesGenerator, generators::RandPrintablesGenerator,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,

View File

@ -15,7 +15,7 @@ use libafl::{
fuzzer::StdFuzzer, fuzzer::StdFuzzer,
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::StdMapObserver, observers::StdMapObserver,
schedulers::{QueueScheduler, Scheduler}, schedulers::{QueueScheduler, Scheduler},
stages::push::{PushStageSharedState, StdMutationalPushStage}, stages::push::{PushStageSharedState, StdMutationalPushStage},

View File

@ -19,7 +19,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},

View File

@ -15,8 +15,8 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::Monitor, monitors::Monitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator,
StdMOptMutator, StdScheduledMutator, Tokens, StdScheduledMutator, Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{ schedulers::{

View File

@ -12,7 +12,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::BytesInput, inputs::BytesInput,
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{CalibrationStage, StdMutationalStage}, stages::{CalibrationStage, StdMutationalStage},

View File

@ -12,7 +12,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::StdMutationalStage, stages::StdMutationalStage,

View File

@ -11,7 +11,7 @@ use libafl::{
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::BytesInput, inputs::BytesInput,
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{CalibrationStage, StdMutationalStage}, stages::{CalibrationStage, StdMutationalStage},

View File

@ -16,7 +16,7 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator,
token_mutations::I2SRandReplace, token_mutations::I2SRandReplace,
}, },
observers::{CanTrack, TimeObserver}, observers::{CanTrack, TimeObserver},

View File

@ -20,7 +20,7 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes, Input}, inputs::{BytesInput, HasTargetBytes, Input},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator,
token_mutations::I2SRandReplace, token_mutations::I2SRandReplace,
}, },
observers::{ observers::{

View File

@ -11,7 +11,7 @@ use libafl_bolts::{
HasLen, HasLen,
}; };
use crate::inputs::HasMutatorBytes; use crate::inputs::{HasMutatorBytes, MappedInput};
/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on /// 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. /// 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)] #[cfg(test)]
mod tests { mod tests {

View File

@ -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<T> MappedInput for Option<T>
where
T: MappedInput,
{
type Type<'a> = Option<T::Type<'a>>
where T: 'a;
}
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`]. /// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
#[derive(Debug)] #[derive(Debug)]
pub struct MutVecInput<'a>(&'a mut Vec<u8>); pub struct MutVecInput<'a>(&'a mut Vec<u8>);
@ -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. /// Defines the input type shared across traits of the type.
/// Needed for consistency across HasCorpus/HasSolutions and friends. /// Needed for consistency across HasCorpus/HasSolutions and friends.
pub trait UsesInput { pub trait UsesInput {

View File

@ -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<I> =
tuple_list_type!(CrossoverInsertMutator<I>, CrossoverReplaceMutator<I>);
/// Tuple type of the mutations that compose the Havoc mutator's crossover mutations for mapped input types
pub type MappedHavocCrossoverType<F, O> = tuple_list_type!(
MappedCrossoverInsertMutator<F, O>,
MappedCrossoverReplaceMutator<F, O>,
);
/// Tuple type of the mutations that compose the Havoc mutator
pub type HavocMutationsType<I> = 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<I>,
CrossoverReplaceMutator<I>,
);
/// Tuple type of the mutations that compose the Havoc mutator for mapped input types
pub type MappedHavocMutationsType<F1, F2, II, O> = tuple_list_type!(
MappedInputFunctionMappingMutator<BitFlipMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteFlipMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteIncMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteDecMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteNegMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteRandMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteAddMutator, F1, II>,
MappedInputFunctionMappingMutator<WordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<DwordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<QwordAddMutator, F1, II>,
MappedInputFunctionMappingMutator<ByteInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<WordInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<DwordInterestingMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesDeleteMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesExpandMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesInsertMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesRandInsertMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesSetMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesRandSetMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesCopyMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesInsertCopyMutator, F1, II>,
MappedInputFunctionMappingMutator<BytesSwapMutator, F1, II>,
MappedInputFunctionMappingMutator<MappedCrossoverInsertMutator<F2, O>, F1, II>,
MappedInputFunctionMappingMutator<MappedCrossoverReplaceMutator<F2, O>, 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<F1, F2, II, O> = tuple_list_type!(
MappedInputFunctionMappingMutator<OptionMappingMutator<BitFlipMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteFlipMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteIncMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteDecMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteNegMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteRandMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<WordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<QwordAddMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<ByteInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<WordInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<DwordInterestingMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesDeleteMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesExpandMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandInsertMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSetMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesRandSetMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesCopyMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesInsertCopyMutator>, F1, II>,
MappedInputFunctionMappingMutator<OptionMappingMutator<BytesSwapMutator>, F1, II>,
MappedInputFunctionMappingMutator<
OptionMappingMutator<MappedCrossoverInsertMutator<F2, O>>,
F1,
II,
>,
MappedInputFunctionMappingMutator<
OptionMappingMutator<MappedCrossoverReplaceMutator<F2, O>>,
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<I>() -> HavocCrossoverType<I> {
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<F, O>(input_mapper: F) -> MappedHavocCrossoverType<F, O>
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<F, O>(
input_mapper: F,
) -> MappedHavocCrossoverType<F, O>
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<I>() -> HavocMutationsType<I> {
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<F1, F2, IO1, IO2, II, O>(
current_input_mapper: F1,
input_from_corpus_mapper: F2,
) -> MappedHavocMutationsType<F1, F2, II, O>
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<F1, F2, IO1, IO2, II, O>(
current_input_mapper: F1,
input_from_corpus_mapper: F2,
) -> OptionMappedHavocMutationsType<F1, F2, II, O>
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,
))
}

View File

@ -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<u8>,);
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
/// &mut input.0
/// }
///
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
/// input.into()
/// }
///
/// // construct a mapper that works on &mut Vec<u8>
/// 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<CustomInput> = 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<M, F> {
mapper: F,
inner: M,
name: Cow<'static, str>,
}
impl<M, F> FunctionMappingMutator<M, F> {
/// 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<M, S, F, IO, II> Mutator<IO, S> for FunctionMappingMutator<M, F>
where
F: for<'a> FnMut(&'a mut IO) -> &'a mut II,
M: Mutator<II, S>,
{
fn mutate(&mut self, state: &mut S, input: &mut IO) -> Result<MutationResult, Error> {
self.inner.mutate(state, (self.mapper)(input))
}
}
impl<M, F> Named for FunctionMappingMutator<M, F> {
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<u8>,);
/// fn extract_to_ref(input: &mut CustomInput) -> &mut Vec<u8> {
/// &mut input.0
/// }
///
/// fn extract_from_ref(input: &mut Vec<u8>) -> MutVecInput<'_> {
/// input.into()
/// }
///
/// // construct a mapper that works on &mut Vec<u8>
/// 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<CustomInput> = 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<F> {
mapper: F,
}
impl<F> ToFunctionMappingMutatorMapper<F> {
/// Creates a new [`ToFunctionMappingMutatorMapper`]
pub fn new(mapper: F) -> Self {
Self { mapper }
}
}
impl<M, F> MappingFunctor<M> for ToFunctionMappingMutatorMapper<F>
where
F: Clone,
M: Named,
{
type Output = FunctionMappingMutator<M, F>;
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<u8>,);
/// 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<CustomInput> = 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<M, F, II> {
mapper: F,
inner: M,
name: Cow<'static, str>,
phantom: PhantomData<II>,
}
impl<M, F, II> MappedInputFunctionMappingMutator<M, F, II> {
/// 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<M, S, F, IO, II> Mutator<IO, S> for MappedInputFunctionMappingMutator<M, F, II>
where
for<'a> M: Mutator<II::Type<'a>, 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<MutationResult, Error> {
let mapped = &mut (self.mapper)(input);
self.inner.mutate(state, mapped)
}
}
impl<M, F, II> Named for MappedInputFunctionMappingMutator<M, F, II> {
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<u8>,);
/// 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<CustomInput> = 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<F, II> {
mapper: F,
phantom: PhantomData<II>,
}
impl<F, II> ToMappedInputFunctionMappingMutatorMapper<F, II> {
/// Creates a new [`ToMappedInputFunctionMappingMutatorMapper`]
pub fn new<IO>(mapper: F) -> Self
where
F: FnMut(IO) -> II,
{
Self {
mapper,
phantom: PhantomData,
}
}
}
impl<M, F, II> MappingFunctor<M> for ToMappedInputFunctionMappingMutatorMapper<F, II>
where
F: Clone,
M: Named,
{
type Output = MappedInputFunctionMappingMutator<M, F, II>;
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<Option<MutVecInput>> = 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<MutVecInput> = None;
/// let res2 = outer.mutate(&mut state, &mut empty_input).unwrap();
/// assert_eq!(res2, MutationResult::Skipped);
/// ```
#[derive(Debug)]
pub struct OptionMappingMutator<M> {
inner: M,
name: Cow<'static, str>,
}
impl<M> OptionMappingMutator<M> {
/// 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<I, S, M> Mutator<Option<I>, S> for OptionMappingMutator<M>
where
M: Mutator<I, S>,
{
fn mutate(&mut self, state: &mut S, input: &mut Option<I>) -> Result<MutationResult, Error> {
match input {
None => Ok(MutationResult::Skipped),
Some(i) => self.inner.mutate(state, i),
}
}
}
impl<M> Named for OptionMappingMutator<M>
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<Option<MutVecInput>> = 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<MutVecInput> = None;
/// let res2 = outer.mutate(&mut state, &mut empty_input).unwrap();
/// assert_eq!(res2, MutationResult::Skipped);
/// ```
#[derive(Debug)]
pub struct ToOptionMappingMutatorMapper;
impl<M> MappingFunctor<M> for ToOptionMappingMutatorMapper
where
M: Named,
{
type Output = OptionMappingMutator<M>;
fn apply(&mut self, from: M) -> Self::Output {
OptionMappingMutator::new(from)
}
}

View File

@ -11,6 +11,8 @@ pub use mutations::*;
pub mod token_mutations; pub mod token_mutations;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub use token_mutations::*; pub use token_mutations::*;
pub mod havoc_mutations;
pub use havoc_mutations::*;
pub mod encoded_mutations; pub mod encoded_mutations;
pub use encoded_mutations::*; pub use encoded_mutations::*;
pub mod mopt_mutator; pub mod mopt_mutator;
@ -19,6 +21,8 @@ pub mod gramatron;
pub use gramatron::*; pub use gramatron::*;
pub mod grimoire; pub mod grimoire;
pub use grimoire::*; pub use grimoire::*;
pub mod mapping;
pub use mapping::*;
pub mod tuneable; pub mod tuneable;
pub use tuneable::*; pub use tuneable::*;

View File

@ -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); return Ok(MutationResult::Skipped);
@ -207,7 +213,7 @@ where
size, size,
target, target,
range, range,
&other.parts()[choice], other.parts()[choice].bytes(),
)) ))
} else { } else {
// just add it! // 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); return Ok(MutationResult::Skipped);
@ -310,7 +316,7 @@ where
part, part,
target, target,
range, range,
&other.parts()[choice], other.parts()[choice].bytes(),
)) ))
} else { } else {
// just add it! // just add it!

View File

@ -10,7 +10,7 @@ use libafl_bolts::{rands::Rand, Named};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
inputs::HasMutatorBytes, inputs::{HasMutatorBytes, UsesInput},
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
random_corpus_id_with_disabled, random_corpus_id_with_disabled,
state::{HasCorpus, HasMaxSize, HasRand}, state::{HasCorpus, HasMaxSize, HasRand},
@ -1030,12 +1030,12 @@ pub struct CrossoverInsertMutator<I> {
} }
impl<I: HasMutatorBytes> CrossoverInsertMutator<I> { impl<I: HasMutatorBytes> CrossoverInsertMutator<I> {
pub(crate) fn crossover_insert<I2: HasMutatorBytes>( pub(crate) fn crossover_insert(
input: &mut I, input: &mut I,
size: usize, size: usize,
target: usize, target: usize,
range: Range<usize>, range: Range<usize>,
other: &I2, other: &[u8],
) -> MutationResult { ) -> MutationResult {
input.resize(size + range.len(), 0); input.resize(size + range.len(), 0);
unsafe { unsafe {
@ -1048,13 +1048,7 @@ impl<I: HasMutatorBytes> CrossoverInsertMutator<I> {
} }
unsafe { unsafe {
buffer_copy( buffer_copy(input.bytes_mut(), other, range.start, target, range.len());
input.bytes_mut(),
other.bytes(),
range.start,
target,
range.len(),
);
} }
MutationResult::Mutated MutationResult::Mutated
} }
@ -1097,7 +1091,13 @@ where
// No need to load the input again, it'll still be cached. // No need to load the input again, it'll still be cached.
let other = other_testcase.input().as_ref().unwrap(); 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<I> {
} }
impl<I: HasMutatorBytes> CrossoverReplaceMutator<I> { impl<I: HasMutatorBytes> CrossoverReplaceMutator<I> {
pub(crate) fn crossover_replace<I2: HasMutatorBytes>( pub(crate) fn crossover_replace(
input: &mut I, input: &mut I,
target: usize, target: usize,
range: Range<usize>, range: Range<usize>,
other: &I2, other: &[u8],
) -> MutationResult { ) -> MutationResult {
unsafe { unsafe {
buffer_copy( buffer_copy(input.bytes_mut(), other, range.start, target, range.len());
input.bytes_mut(),
other.bytes(),
range.start,
target,
range.len(),
);
} }
MutationResult::Mutated MutationResult::Mutated
} }
@ -1180,7 +1174,7 @@ where
// No need to load the input again, it'll still be cached. // No need to load the input again, it'll still be cached.
let other = other_testcase.input().as_ref().unwrap(); 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<I> CrossoverReplaceMutator<I> {
} }
} }
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<F, O> {
input_mapper: F,
phantom: PhantomData<O>,
}
impl<F, O> MappedCrossoverInsertMutator<F, O> {
/// Creates a new [`MappedCrossoverInsertMutator`]
pub fn new(input_mapper: F) -> Self {
Self {
input_mapper,
phantom: PhantomData,
}
}
}
impl<S, F, I, O> Mutator<I, S> for MappedCrossoverInsertMutator<F, O>
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) -> <O as IntoOptionBytes>::Type<'a>,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
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<F, O> Named for MappedCrossoverInsertMutator<F, O> {
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<F, O> {
input_mapper: F,
phantom: PhantomData<O>,
}
impl<F, O> MappedCrossoverReplaceMutator<F, O> {
/// Creates a new [`MappedCrossoverReplaceMutator`]
pub fn new(input_mapper: F) -> Self {
Self {
input_mapper,
phantom: PhantomData,
}
}
}
impl<S, F, I, O> Mutator<I, S> for MappedCrossoverReplaceMutator<F, O>
where
S: HasCorpus + HasMaxSize + HasRand + UsesInput,
I: HasMutatorBytes,
O: IntoOptionBytes,
for<'a> O::Type<'a>: IntoOptionBytes,
for<'a> F: Fn(&'a S::Input) -> <O as IntoOptionBytes>::Type<'a>,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
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<F, O> Named for MappedCrossoverReplaceMutator<F, O> {
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 /// 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) { fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
let mut first_diff: i64 = -1; let mut first_diff: i64 = -1;

View File

@ -9,7 +9,7 @@ use core::{
use libafl_bolts::{ use libafl_bolts::{
rands::Rand, rands::Rand,
tuples::{tuple_list, tuple_list_type, Merge, NamedTuple}, tuples::{tuple_list, tuple_list_type, NamedTuple},
Named, Named,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -18,14 +18,6 @@ use super::MutationId;
use crate::{ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
mutators::{ 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}, token_mutations::{TokenInsert, TokenReplace},
MutationResult, Mutator, MutatorsTuple, 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<I> =
tuple_list_type!(CrossoverInsertMutator<I>, CrossoverReplaceMutator<I>);
/// Tuple type of the mutations that compose the Havoc mutator
pub type HavocMutationsType<I> = 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<I>,
CrossoverReplaceMutator<I>,
);
/// 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<I>() -> HavocCrossoverType<I> {
tuple_list!(
CrossoverInsertMutator::new(),
CrossoverReplaceMutator::new(),
)
}
/// Get the mutations that compose the Havoc mutator
#[must_use]
pub fn havoc_mutations<I>() -> HavocMutationsType<I> {
havoc_mutations_no_crossover().merge(havoc_crossover())
}
/// Get the mutations that uses the Tokens metadata /// Get the mutations that uses the Tokens metadata
#[must_use] #[must_use]
pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) { pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) {
@ -482,9 +363,8 @@ mod tests {
feedbacks::ConstFeedback, feedbacks::ConstFeedback,
inputs::{BytesInput, HasMutatorBytes}, inputs::{BytesInput, HasMutatorBytes},
mutators::{ mutators::{
mutations::SpliceMutator, havoc_mutations::havoc_mutations, mutations::SpliceMutator,
scheduled::{havoc_mutations, StdScheduledMutator}, scheduled::StdScheduledMutator, Mutator,
Mutator,
}, },
state::StdState, state::StdState,
}; };

View File

@ -12,7 +12,8 @@ use libafl::{
generators::RandBytesGenerator, generators::RandBytesGenerator,
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -15,7 +15,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},

View File

@ -17,7 +17,8 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::{ mutators::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, havoc_mutations::havoc_mutations,
scheduled::{tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
I2SRandReplace, I2SRandReplace,
}, },