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:
parent
5b7d307a6a
commit
2c676f0352
1
.github/workflows/build_and_test.yml
vendored
1
.github/workflows/build_and_test.yml
vendored
@ -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
|
||||
|
@ -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,
|
||||
|
24
fuzzers/baby/baby_fuzzer_custom_input/Cargo.toml
Normal file
24
fuzzers/baby/baby_fuzzer_custom_input/Cargo.toml
Normal 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 = "*"
|
7
fuzzers/baby/baby_fuzzer_custom_input/README.md
Normal file
7
fuzzers/baby/baby_fuzzer_custom_input/README.md
Normal 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`.
|
147
fuzzers/baby/baby_fuzzer_custom_input/src/input.rs
Normal file
147
fuzzers/baby/baby_fuzzer_custom_input/src/input.rs
Normal 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")
|
||||
}
|
||||
}
|
206
fuzzers/baby/baby_fuzzer_custom_input/src/main.rs
Normal file
206
fuzzers/baby/baby_fuzzer_custom_input/src/main.rs
Normal 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");
|
||||
}
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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::{
|
||||
|
@ -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::{
|
||||
|
@ -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::{
|
||||
|
@ -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,
|
||||
|
@ -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::{
|
||||
|
@ -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::{
|
||||
|
@ -30,7 +30,7 @@ use libafl::{
|
||||
GrimoireExtensionMutator, GrimoireRandomDeleteMutator,
|
||||
GrimoireRecursiveReplacementMutator, GrimoireStringReplacementMutator,
|
||||
},
|
||||
scheduled::havoc_mutations,
|
||||
havoc_mutations,
|
||||
token_mutations::I2SRandReplace,
|
||||
tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens,
|
||||
},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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::{
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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::{
|
||||
|
@ -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},
|
||||
|
@ -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,
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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::{
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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`].
|
||||
#[derive(Debug)]
|
||||
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.
|
||||
/// Needed for consistency across HasCorpus/HasSolutions and friends.
|
||||
pub trait UsesInput {
|
||||
|
272
libafl/src/mutators/havoc_mutations.rs
Normal file
272
libafl/src/mutators/havoc_mutations.rs
Normal 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,
|
||||
))
|
||||
}
|
414
libafl/src/mutators/mapping.rs
Normal file
414
libafl/src/mutators/mapping.rs
Normal 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)
|
||||
}
|
||||
}
|
@ -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::*;
|
||||
|
||||
|
@ -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!
|
||||
|
@ -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<I> {
|
||||
}
|
||||
|
||||
impl<I: HasMutatorBytes> CrossoverInsertMutator<I> {
|
||||
pub(crate) fn crossover_insert<I2: HasMutatorBytes>(
|
||||
pub(crate) fn crossover_insert(
|
||||
input: &mut I,
|
||||
size: usize,
|
||||
target: usize,
|
||||
range: Range<usize>,
|
||||
other: &I2,
|
||||
other: &[u8],
|
||||
) -> MutationResult {
|
||||
input.resize(size + range.len(), 0);
|
||||
unsafe {
|
||||
@ -1048,13 +1048,7 @@ impl<I: HasMutatorBytes> CrossoverInsertMutator<I> {
|
||||
}
|
||||
|
||||
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<I> {
|
||||
}
|
||||
|
||||
impl<I: HasMutatorBytes> CrossoverReplaceMutator<I> {
|
||||
pub(crate) fn crossover_replace<I2: HasMutatorBytes>(
|
||||
pub(crate) fn crossover_replace(
|
||||
input: &mut I,
|
||||
target: usize,
|
||||
range: Range<usize>,
|
||||
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<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
|
||||
fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||
let mut first_diff: i64 = -1;
|
||||
|
@ -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<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
|
||||
#[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,
|
||||
};
|
||||
|
@ -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},
|
||||
|
@ -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},
|
||||
|
@ -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,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user