Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deriving Mapping Mutators #2585

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions fuzzers/structure_aware/baby_fuzzer_custom_input/src/main.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ use libafl::{
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::MutVecInput,
monitors::SimpleMonitor,
mutators::scheduled::StdScheduledMutator,
observers::StdMapObserver,
@@ -138,14 +139,17 @@ pub fn main() {
#[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);
let mapped_mutators = mapped_havoc_mutations::<CustomInput, MutVecInput<'_>, &[u8]>(
CustomInput::byte_array_mut,
CustomInput::byte_array,
);

// 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,
);
let optional_mapped_mutators =
optional_mapped_havoc_mutations::<_, Option<MutVecInput<'_>>, Option<&[u8]>>(
CustomInput::optional_byte_array_mut,
CustomInput::optional_byte_array,
);
(mapped_mutators, optional_mapped_mutators)
};

309 changes: 178 additions & 131 deletions libafl/src/mutators/havoc_mutations.rs

Large diffs are not rendered by default.

63 changes: 36 additions & 27 deletions libafl/src/mutators/mapping.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! 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};

@@ -58,6 +57,7 @@ pub struct FunctionMappingMutator<M, F> {

impl<M, F> FunctionMappingMutator<M, F> {
/// Creates a new [`FunctionMappingMutator`]
#[must_use]
pub fn new(mapper: F, inner: M) -> Self
where
M: Named,
@@ -137,6 +137,7 @@ pub struct ToFunctionMappingMutatorMapper<F> {

impl<F> ToFunctionMappingMutatorMapper<F> {
/// Creates a new [`ToFunctionMappingMutatorMapper`]
#[must_use]
pub fn new(mapper: F) -> Self {
Self { mapper }
}
@@ -188,16 +189,22 @@ where
/// assert_eq!(input, (vec![2],));
/// ```
#[derive(Debug)]
pub struct MappedInputFunctionMappingMutator<M, F, II> {
mapper: F,
pub struct MappedInputFunctionMappingMutator<M, IO, II>
where
II: MappedInput,
{
mapper: for<'a> fn(&'a mut IO) -> II::Type<'a>,
inner: M,
name: Cow<'static, str>,
phantom: PhantomData<II>,
}

impl<M, F, II> MappedInputFunctionMappingMutator<M, F, II> {
impl<M, IO, II> MappedInputFunctionMappingMutator<M, IO, II>
where
II: MappedInput,
{
/// Creates a new [`MappedInputFunctionMappingMutator`]
pub fn new(mapper: F, inner: M) -> Self
#[must_use]
pub fn new(mapper: for<'a> fn(&'a mut IO) -> II::Type<'a>, inner: M) -> Self
where
M: Named,
{
@@ -210,24 +217,25 @@ impl<M, F, II> MappedInputFunctionMappingMutator<M, F, II> {
mapper,
inner,
name,
phantom: PhantomData,
}
}
}

impl<M, S, F, IO, II> Mutator<IO, S> for MappedInputFunctionMappingMutator<M, F, II>
impl<M, S, IO, II> Mutator<IO, S> for MappedInputFunctionMappingMutator<M, IO, 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>,
II: MappedInput,
{
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> {
impl<M, IO, II> Named for MappedInputFunctionMappingMutator<M, IO, II>
where
II: MappedInput,
{
fn name(&self) -> &Cow<'static, str> {
&self.name
}
@@ -271,33 +279,33 @@ impl<M, F, II> Named for MappedInputFunctionMappingMutator<M, F, II> {
/// assert_eq!(input, (vec![2],));
/// ```
#[derive(Debug)]
pub struct ToMappedInputFunctionMappingMutatorMapper<F, II> {
mapper: F,
phantom: PhantomData<II>,
pub struct ToMappedInputFunctionMappingMutatorMapper<IO, II>
where
II: MappedInput,
{
mapper: for<'a> fn(&'a mut IO) -> II::Type<'a>,
}

impl<F, II> ToMappedInputFunctionMappingMutatorMapper<F, II> {
impl<IO, II> ToMappedInputFunctionMappingMutatorMapper<IO, II>
where
II: MappedInput,
{
/// Creates a new [`ToMappedInputFunctionMappingMutatorMapper`]
pub fn new<IO>(mapper: F) -> Self
where
F: FnMut(IO) -> II,
{
Self {
mapper,
phantom: PhantomData,
}
#[must_use]
pub fn new(mapper: for<'a> fn(&'a mut IO) -> II::Type<'a>) -> Self {
Self { mapper }
}
}

impl<M, F, II> MappingFunctor<M> for ToMappedInputFunctionMappingMutatorMapper<F, II>
impl<M, II, IO> MappingFunctor<M> for ToMappedInputFunctionMappingMutatorMapper<IO, II>
where
F: Clone,
M: Named,
II: MappedInput,
{
type Output = MappedInputFunctionMappingMutator<M, F, II>;
type Output = MappedInputFunctionMappingMutator<M, IO, II>;

fn apply(&mut self, from: M) -> Self::Output {
MappedInputFunctionMappingMutator::new(self.mapper.clone(), from)
MappedInputFunctionMappingMutator::new(self.mapper, from)
}
}

@@ -339,6 +347,7 @@ pub struct OptionMappingMutator<M> {

impl<M> OptionMappingMutator<M> {
/// Creates a new [`OptionMappingMutator`]
#[must_use]
pub fn new(inner: M) -> Self
where
M: Named,
9 changes: 9 additions & 0 deletions libafl/src/mutators/mod.rs
Original file line number Diff line number Diff line change
@@ -397,3 +397,12 @@ impl Named for NopMutator {
&Cow::Borrowed("NopMutator")
}
}

/// Extensions of [`crate::inputs::Input`]s that have default mutators
pub trait DefaultMutators {
/// The resulting mutator list type
type Type;
/// Get the default mutators for this type
#[must_use]
fn default_mutators() -> Self::Type;
}
76 changes: 46 additions & 30 deletions libafl/src/mutators/mutations.rs
Original file line number Diff line number Diff line change
@@ -6,7 +6,6 @@ use alloc::{
};
use core::{
cmp::min,
marker::PhantomData,
mem::size_of,
num::{NonZero, NonZeroUsize},
ops::Range,
@@ -1279,9 +1278,12 @@ impl CrossoverReplaceMutator {
}
}

trait IntoOptionBytes {
/// Anything that can be mapped to `Option<&[u8]>`, ensuring that the lifetime of the input and output are the same
pub trait IntoOptionBytes {
/// Should be Self, ensure that the lifetimes match
type Type<'b>;

/// Run the mapping
fn into_option_bytes<'a>(self) -> Option<&'a [u8]>
where
Self: 'a;
@@ -1311,28 +1313,32 @@ impl IntoOptionBytes for Option<&[u8]> {

/// Crossover insert mutation for inputs mapped to a bytes vector
#[derive(Debug)]
pub struct MappedCrossoverInsertMutator<F, O> {
input_mapper: F,
phantom: PhantomData<O>,
pub struct MappedCrossoverInsertMutator<IO, II>
where
II: IntoOptionBytes,
{
input_mapper: for<'a> fn(&'a IO) -> II::Type<'a>,
}

impl<F, O> MappedCrossoverInsertMutator<F, O> {
impl<IO, II> MappedCrossoverInsertMutator<IO, II>
where
II: IntoOptionBytes,
{
/// Creates a new [`MappedCrossoverInsertMutator`]
pub fn new(input_mapper: F) -> Self {
Self {
input_mapper,
phantom: PhantomData,
}
#[must_use]
pub fn new(input_mapper: fn(&IO) -> II::Type<'_>) -> Self {
Self { input_mapper }
}
}

impl<S, F, I, O> Mutator<I, S> for MappedCrossoverInsertMutator<F, O>
impl<S, I, IO, II> Mutator<I, S> for MappedCrossoverInsertMutator<IO, II>
where
II: IntoOptionBytes,
S: HasCorpus + HasMaxSize + HasRand,
S::Corpus: Corpus<Input = IO>,
I: HasMutatorBytes,
for<'a> O: IntoOptionBytes,
for<'a> O::Type<'a>: IntoOptionBytes,
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
for<'a> II: IntoOptionBytes,
for<'a> II::Type<'a>: IntoOptionBytes,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len();
@@ -1392,7 +1398,10 @@ where
}
}

impl<F, O> Named for MappedCrossoverInsertMutator<F, O> {
impl<IO, II> Named for MappedCrossoverInsertMutator<IO, II>
where
II: IntoOptionBytes,
{
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverInsertMutator");
&NAME
@@ -1401,28 +1410,32 @@ impl<F, O> Named for MappedCrossoverInsertMutator<F, O> {

/// Crossover replace mutation for inputs mapped to a bytes vector
#[derive(Debug)]
pub struct MappedCrossoverReplaceMutator<F, O> {
input_mapper: F,
phantom: PhantomData<O>,
pub struct MappedCrossoverReplaceMutator<IO, II>
where
II: IntoOptionBytes,
{
input_mapper: for<'a> fn(&'a IO) -> II::Type<'a>,
}

impl<F, O> MappedCrossoverReplaceMutator<F, O> {
impl<IO, II> MappedCrossoverReplaceMutator<IO, II>
where
II: IntoOptionBytes,
{
/// Creates a new [`MappedCrossoverReplaceMutator`]
pub fn new(input_mapper: F) -> Self {
Self {
input_mapper,
phantom: PhantomData,
}
#[must_use]
pub fn new(input_mapper: fn(&IO) -> II::Type<'_>) -> Self {
Self { input_mapper }
}
}

impl<S, F, I, O> Mutator<I, S> for MappedCrossoverReplaceMutator<F, O>
impl<S, I, IO, II> Mutator<I, S> for MappedCrossoverReplaceMutator<IO, II>
where
II: IntoOptionBytes,
S: HasCorpus + HasMaxSize + HasRand,
S::Corpus: Corpus<Input = IO>,
I: HasMutatorBytes,
O: IntoOptionBytes,
for<'a> O::Type<'a>: IntoOptionBytes,
for<'a> F: Fn(&'a <S::Corpus as Corpus>::Input) -> <O as IntoOptionBytes>::Type<'a>,
for<'a> II: IntoOptionBytes,
for<'a> II::Type<'a>: IntoOptionBytes,
{
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len();
@@ -1479,7 +1492,10 @@ where
}
}

impl<F, O> Named for MappedCrossoverReplaceMutator<F, O> {
impl<IO, II> Named for MappedCrossoverReplaceMutator<IO, II>
where
II: IntoOptionBytes,
{
fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("MappedCrossoverReplaceMutator");
&NAME
31 changes: 31 additions & 0 deletions libafl_bolts/src/tuples.rs
Original file line number Diff line number Diff line change
@@ -865,6 +865,37 @@ impl<Head, Tail> PlusOne for (Head, Tail) where

*/

/// Merge two lists of types created by the [`tuple_list_type`] macro
///
/// ```rust
/// use libafl_bolts::{merge_tuple_list_type, tuples::{Merge, tuple_list, tuple_list_type}};
/// #[derive(PartialEq, Debug)]
/// struct T1;
/// #[derive(PartialEq, Debug)]
/// struct T2;
/// #[derive(PartialEq, Debug)]
/// struct T3;
/// #[derive(PartialEq, Debug)]
/// struct T4;
/// #[derive(PartialEq, Debug)]
/// struct T5;
///
/// type List1 = tuple_list_type!(T1, T2);
/// let list1: List1 = tuple_list!(T1, T2);
/// type List2 = tuple_list_type!(T3, T4, T5);
/// let list2: List2 = tuple_list!(T3, T4, T5);
/// type Combined = merge_tuple_list_type!(List1, List2);
/// let combined: Combined = list1.merge(list2);
/// let manual: Combined = tuple_list!(T1, T2, T3, T4, T5);
/// assert_eq!(combined, manual);
/// ```
#[macro_export]
macro_rules! merge_tuple_list_type {
($Type1:ty, $Type2:ty) => {
<$Type1 as $crate::tuples::Merge<$Type2>>::MergeResult
};
}

#[cfg(test)]
mod test {
use tuple_list::{tuple_list, tuple_list_type};
1 change: 1 addition & 0 deletions libafl_derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ proc-macro = true
syn = { version = "2.0.77", features = ["full", "extra-traits"] }
quote = "1.0.37"
proc-macro2 = "1.0.86"
proc-macro-crate = "3.2"

[lints]
workspace = true
Loading