Add BytesSubInput to mutate sub-parts of a bytes-backed input (#2220)

* Add BytesSubMutator that allows us to mutate sub-parts of a bytes-backed input

* no_std

* fix string mutator

* make build

* Fix clippy on macOS

* Docs

* More docs

* Better docs

* --amend

* Renamed bsi to sub_input. Too much BSI

* More more

* balance backticks

* Make splicing usable with sub_input (not that it makes sense)

* More annotations

* more input annotations?

* Implement HasMutatorBytes for &mut Vec

* clippy

* Use a wrapper type instead

* Add wrapper type for Vec as well

* Remove the duplicate BytesInput... lol
This commit is contained in:
Dominik Maier 2024-05-22 01:50:07 +02:00 committed by GitHub
parent 19ef29ed60
commit 684b31279e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 634 additions and 101 deletions

View File

@ -94,8 +94,8 @@ pub fn main() -> Result<(), Error> {
.expect("Failed to generate the initial corpus"); .expect("Failed to generate the initial corpus");
// Setup a mutational stage with a basic bytes mutator // Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::new(havoc_mutations()); let mutator = StdScheduledMutator::new(havoc_mutations::<BytesInput>());
let minimizer = StdScheduledMutator::new(havoc_mutations()); let minimizer = StdScheduledMutator::new(havoc_mutations::<BytesInput>());
let mut stages = tuple_list!( let mut stages = tuple_list!(
StdMutationalStage::new(mutator), StdMutationalStage::new(mutator),
StdTMinMutationalStage::new(minimizer, factory, 128) StdTMinMutationalStage::new(minimizer, factory, 128)
@ -121,7 +121,7 @@ pub fn main() -> Result<(), Error> {
let mut mgr = SimpleEventManager::new(mon); let mut mgr = SimpleEventManager::new(mon);
let minimizer = StdScheduledMutator::new(havoc_mutations()); let minimizer = StdScheduledMutator::new(havoc_mutations::<BytesInput>());
let mut stages = tuple_list!(StdTMinMutationalStage::new( let mut stages = tuple_list!(StdTMinMutationalStage::new(
minimizer, minimizer,
CrashFeedback::new(), CrashFeedback::new(),

View File

@ -1,4 +1,4 @@
//! The testcase is a struct embedded in each corpus. //! The [`Testcase`] is a struct embedded in each [`Corpus`].
//! It will contain a respective input, and metadata. //! It will contain a respective input, and metadata.
use alloc::string::String; use alloc::string::String;
@ -34,7 +34,7 @@ pub trait HasTestcase: UsesInput {
) -> Result<RefMut<Testcase<<Self as UsesInput>::Input>>, Error>; ) -> Result<RefMut<Testcase<<Self as UsesInput>::Input>>, Error>;
} }
/// An entry in the Testcase Corpus /// An entry in the [`Testcase`] Corpus
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")] #[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct Testcase<I> pub struct Testcase<I>

View File

@ -15,7 +15,7 @@ use libafl_bolts::{fs::write_file_atomic, Error};
use libafl_bolts::{ownedref::OwnedSlice, HasLen}; use libafl_bolts::{ownedref::OwnedSlice, HasLen};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::inputs::{HasBytesVec, HasTargetBytes, Input}; use crate::inputs::{HasMutatorBytes, HasTargetBytes, Input};
/// A bytes input is the basic input /// A bytes input is the basic input
#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)]
@ -61,16 +61,39 @@ impl From<BytesInput> for Rc<RefCell<BytesInput>> {
} }
} }
impl HasBytesVec for BytesInput { impl HasMutatorBytes for BytesInput {
#[inline] #[inline]
fn bytes(&self) -> &[u8] { fn bytes(&self) -> &[u8] {
&self.bytes &self.bytes
} }
#[inline] #[inline]
fn bytes_mut(&mut self) -> &mut Vec<u8> { fn bytes_mut(&mut self) -> &mut [u8] {
&mut self.bytes &mut self.bytes
} }
fn resize(&mut self, new_len: usize, value: u8) {
self.bytes.resize(new_len, value);
}
fn extend<'a, I: IntoIterator<Item = &'a u8>>(&mut self, iter: I) {
Extend::extend(&mut self.bytes, iter);
}
fn splice<R, I>(&mut self, range: R, replace_with: I) -> alloc::vec::Splice<'_, I::IntoIter>
where
R: core::ops::RangeBounds<usize>,
I: IntoIterator<Item = u8>,
{
self.bytes.splice(range, replace_with)
}
fn drain<R>(&mut self, range: R) -> alloc::vec::Drain<'_, u8>
where
R: core::ops::RangeBounds<usize>,
{
self.bytes.drain(range)
}
} }
impl HasTargetBytes for BytesInput { impl HasTargetBytes for BytesInput {

View File

@ -0,0 +1,426 @@
//! [`BytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice
use alloc::vec::Vec;
use core::{
cmp::{min, Ordering},
ops::{Bound, Range, RangeBounds},
};
use libafl_bolts::HasLen;
use super::HasMutatorBytes;
/// Gets the relevant concrete start index from [`RangeBounds`] (inclusive)
fn start_index<R>(range: &R) -> usize
where
R: RangeBounds<usize>,
{
match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(start) => *start,
Bound::Excluded(start) => start + 1,
}
}
/// Gets the relevant concrete end index from [`RangeBounds`] (exclusive)
fn end_index<R>(range: &R, max_len: usize) -> usize
where
R: RangeBounds<usize>,
{
match range.end_bound() {
Bound::Unbounded => max_len,
Bound::Included(end) => end + 1,
Bound::Excluded(end) => *end,
}
}
/// 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.
/// For example, we can do the following:
/// ```rust
/// # extern crate alloc;
/// # extern crate libafl;
/// # use libafl::inputs::{BytesInput, HasMutatorBytes};
/// # use alloc::vec::Vec;
/// #
/// # #[cfg(not(feature = "std"))]
/// # #[no_mangle]
/// # pub extern "C" fn external_current_millis() -> u64 { 0 }
///
/// let mut bytes_input = BytesInput::new(vec![1,2,3]);
/// let mut sub_input = bytes_input.sub_input(1..);
///
/// // Run any mutations on the sub input.
/// sub_input.bytes_mut()[0] = 42;
///
/// // The mutations are applied to the underlying input.
/// assert_eq!(bytes_input.bytes()[1], 42);
/// ```
///
/// Growing or shrinking the sub input will grow or shrink the parent input,
/// and keep elements around the current range untouched / move them accordingly.
///
/// For example:
/// ```rust
/// # extern crate alloc;
/// # extern crate libafl;
/// # use libafl::inputs::{BytesInput, HasMutatorBytes};
/// # use alloc::vec::Vec;
/// #
/// # #[cfg(not(feature = "std"))]
/// # #[no_mangle]
/// # pub extern "C" fn external_current_millis() -> u64 { 0 }
///
/// let mut bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5]);
///
/// // Note that the range ends on an exclusive value this time.
/// let mut sub_input = bytes_input.sub_input(1..=3);
///
/// assert_eq!(sub_input.bytes(), &[2, 3, 4]);
///
/// // We extend it with a few values.
/// sub_input.extend(&[42, 42, 42]);
///
/// // The values outside of the range are moved back and forwards, accordingly.
/// assert_eq!(bytes_input.bytes(), [1, 2, 3, 4, 42, 42, 42, 5]);
/// ```
///
/// The input supports all methods in the [`HasMutatorBytes`] trait.
#[derive(Debug)]
pub struct BytesSubInput<'a, I>
where
I: HasMutatorBytes + ?Sized,
{
/// The (complete) parent input we will work on
pub(crate) parent_input: &'a mut I,
/// The range inside the parent input we will work on
pub(crate) range: Range<usize>,
}
impl<'a, I> BytesSubInput<'a, I>
where
I: HasMutatorBytes + ?Sized + HasLen,
{
/// Creates a new [`BytesSubInput`] that's a view on an input with mutator bytes.
/// The sub input can then be used to mutate parts of the original input.
pub fn new<R>(parent_input: &'a mut I, range: R) -> Self
where
R: RangeBounds<usize>,
{
let parent_len = parent_input.len();
BytesSubInput {
parent_input,
range: Range {
start: start_index(&range),
end: end_index(&range, parent_len),
},
}
}
/// The inclusive start index in the parent buffer
fn start_index(&self) -> usize {
self.range.start
}
/// The exclusive end index in the parent buffer
fn end_index(&self) -> usize {
self.range.end
}
/// Creates a sub range in the current own range
fn sub_range<R2>(&self, range: R2) -> (Bound<usize>, Bound<usize>)
where
R2: RangeBounds<usize>,
{
let start = match (self.range.start_bound(), range.start_bound()) {
(Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded,
(Bound::Excluded(bound), Bound::Unbounded)
| (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(*bound),
(Bound::Included(bound), Bound::Unbounded)
| (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(*bound),
(Bound::Included(own), Bound::Included(other)) => Bound::Included(own + other),
(Bound::Included(own), Bound::Excluded(other))
| (Bound::Excluded(own), Bound::Included(other)) => Bound::Excluded(own + other),
(Bound::Excluded(own), Bound::Excluded(other)) => Bound::Excluded(own + other + 1),
};
let end = match (self.range.end_bound(), range.end_bound()) {
(Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded,
(Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound),
(Bound::Unbounded, Bound::Excluded(bound)) => {
Bound::Excluded(self.end_index() - *bound)
}
(Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound),
(Bound::Unbounded, Bound::Included(bound)) => {
Bound::Included(self.end_index() - *bound)
}
(Bound::Included(own), Bound::Included(other)) => {
Bound::Included(min(*own, self.start_index() + other))
}
(Bound::Included(own), Bound::Excluded(other)) => {
Bound::Included(min(*own, self.start_index() + other - 1))
}
(Bound::Excluded(own), Bound::Included(other)) => {
Bound::Included(min(*own - 1, self.start_index() + other))
}
(Bound::Excluded(own), Bound::Excluded(other)) => {
Bound::Excluded(min(*own, self.start_index() + other))
}
};
(start, end)
}
}
impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I>
where
I: HasMutatorBytes + HasLen,
{
#[inline]
fn bytes(&self) -> &[u8] {
&self.parent_input.bytes()[self.range.clone()]
}
#[inline]
fn bytes_mut(&mut self) -> &mut [u8] {
&mut self.parent_input.bytes_mut()[self.range.clone()]
}
fn resize(&mut self, new_len: usize, value: u8) {
let start_index = self.start_index();
let end_index = self.end_index();
let old_len = end_index - start_index;
match new_len.cmp(&old_len) {
Ordering::Equal => {
// Nothing to do here.
}
Ordering::Greater => {
// We grow. Resize the underlying buffer, then move the entries past our `end_index` back.
let diff = new_len - old_len;
let old_parent_len = self.parent_input.len();
self.parent_input.resize(old_parent_len + diff, value);
if old_parent_len > end_index {
// the parent has a reminder, move it back.
let parent_bytes = self.parent_input.bytes_mut();
// move right
let (_, rest) = parent_bytes.split_at_mut(start_index + old_len);
rest.copy_within(0..rest.len() - diff, diff);
let (new, _rest) = rest.split_at_mut(diff);
// fill
new.fill(value);
}
self.range.end += diff;
}
Ordering::Less => {
// We shrink. Remove the values, then remove the underlying buffer.
let diff = old_len - new_len;
let parent_bytes = self.parent_input.bytes_mut();
// move left
let (_, rest) = parent_bytes.split_at_mut(start_index + new_len);
rest.copy_within(diff.., 0);
// cut off the rest
self.parent_input
.resize(self.parent_input.len() - diff, value);
self.range.end -= diff;
}
}
}
fn extend<'b, IT: IntoIterator<Item = &'b u8>>(&mut self, iter: IT) {
let old_len = self.end_index() - self.start_index();
let new_values: Vec<u8> = iter.into_iter().copied().collect();
self.resize(old_len + new_values.len(), 0);
self.bytes_mut()[old_len..].copy_from_slice(&new_values);
}
/// Creates a splicing iterator that replaces the specified range in the vector
/// with the given `replace_with` iterator and yields the removed items.
/// `replace_with` does not need to be the same length as range.
/// Refer to the docs of [`Vec::splice`]
fn splice<R2, IT>(
&mut self,
range: R2,
replace_with: IT,
) -> alloc::vec::Splice<'_, IT::IntoIter>
where
R2: RangeBounds<usize>,
IT: IntoIterator<Item = u8>,
{
let range = self.sub_range(range);
self.parent_input.splice(range, replace_with)
}
fn drain<R2>(&mut self, range: R2) -> alloc::vec::Drain<'_, u8>
where
R2: RangeBounds<usize>,
{
let drain = self.parent_input.drain(self.sub_range(range));
self.range.end -= drain.len();
drain
}
}
impl<'a, I> HasLen for BytesSubInput<'a, I>
where
I: HasMutatorBytes + HasLen,
{
#[inline]
fn len(&self) -> usize {
self.range.end - self.range.start
}
}
#[cfg(test)]
mod tests {
use alloc::vec::Vec;
use libafl_bolts::HasLen;
use crate::{
inputs::{BytesInput, HasMutatorBytes, MutVecInput, NopInput},
mutators::{havoc_mutations_no_crossover, MutatorsTuple},
state::NopState,
};
fn init_bytes_input() -> (BytesInput, usize) {
let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]);
let len_orig = bytes_input.len();
(bytes_input, len_orig)
}
#[test]
fn test_bytessubinput() {
let (mut bytes_input, len_orig) = init_bytes_input();
let mut sub_input = bytes_input.sub_input(0..1);
assert_eq!(sub_input.len(), 1);
sub_input.bytes_mut()[0] = 2;
assert_eq!(bytes_input.bytes()[0], 2);
let mut sub_input = bytes_input.sub_input(1..=2);
assert_eq!(sub_input.len(), 2);
sub_input.bytes_mut()[0] = 3;
assert_eq!(bytes_input.bytes()[1], 3);
let mut sub_input = bytes_input.sub_input(..);
assert_eq!(sub_input.len(), len_orig);
sub_input.bytes_mut()[0] = 1;
sub_input.bytes_mut()[1] = 2;
assert_eq!(bytes_input.bytes()[0], 1);
}
#[test]
fn test_bytessubinput_resize() {
let (mut bytes_input, len_orig) = init_bytes_input();
let bytes_input_orig = bytes_input.clone();
let mut sub_input = bytes_input.sub_input(2..);
assert_eq!(sub_input.len(), len_orig - 2);
sub_input.resize(len_orig, 0);
assert_eq!(sub_input.bytes()[sub_input.len() - 1], 0);
assert_eq!(sub_input.len(), len_orig);
assert_eq!(bytes_input.len(), len_orig + 2);
assert_eq!(bytes_input.bytes()[bytes_input.len() - 1], 0);
let (mut bytes_input, len_orig) = init_bytes_input();
let mut sub_input = bytes_input.sub_input(..2);
assert_eq!(sub_input.len(), 2);
sub_input.resize(3, 0);
assert_eq!(sub_input.len(), 3);
assert_eq!(sub_input.bytes()[sub_input.len() - 1], 0);
assert_eq!(bytes_input.len(), len_orig + 1);
let mut sub_input = bytes_input.sub_input(..3);
assert_eq!(sub_input.len(), 3);
sub_input.resize(2, 0);
assert_eq!(sub_input.len(), 2);
assert_eq!(bytes_input, bytes_input_orig);
let mut sub_input = bytes_input.sub_input(2..=2);
sub_input.resize(2, 0);
sub_input.resize(1, 0);
assert_eq!(bytes_input, bytes_input_orig);
let mut sub_input = bytes_input.sub_input(..);
assert_eq!(sub_input.len(), bytes_input_orig.len());
sub_input.resize(1, 0);
assert_eq!(sub_input.len(), 1);
sub_input.resize(10, 0);
assert_eq!(sub_input.len(), 10);
assert_eq!(bytes_input.len(), 10);
assert_eq!(bytes_input.bytes()[2], 0);
let mut sub_input = bytes_input.sub_input(..);
sub_input.resize(1, 0);
assert_eq!(bytes_input.len(), 1);
}
#[test]
fn test_bytessubinput_drain_extend() {
let (mut bytes_input, len_orig) = init_bytes_input();
let bytes_input_cloned = bytes_input.clone();
let mut sub_input = bytes_input.sub_input(..2);
let drained: Vec<_> = sub_input.drain(..).collect();
assert_eq!(sub_input.len(), 0);
assert_eq!(bytes_input.len(), len_orig - 2);
let mut sub_input = bytes_input.sub_input(..0);
assert_eq!(sub_input.len(), 0);
let drained_len = drained.len();
sub_input.extend(&drained[..]);
assert_eq!(sub_input.len(), drained_len);
assert_eq!(bytes_input, bytes_input_cloned);
}
#[test]
fn test_bytessubinput_mutator() {
let (mut bytes_input, _len_orig) = init_bytes_input();
let bytes_input_cloned = bytes_input.clone();
let mut sub_input = bytes_input.sub_input(..2);
// Note that if you want to use NopState in production like this, you should see the rng! :)
let mut state: NopState<NopInput> = NopState::new();
let result = havoc_mutations_no_crossover().mutate_all(&mut state, &mut sub_input);
assert!(result.is_ok());
assert_ne!(bytes_input, bytes_input_cloned);
}
#[test]
fn test_bytessubinput_use_vec() {
let mut test_vec = vec![0, 1, 2, 3, 4];
let mut test_vec = MutVecInput::from(&mut test_vec);
let mut sub_vec = test_vec.sub_input(1..2);
drop(sub_vec.drain(..));
assert_eq!(test_vec.len(), 4);
}
#[test]
fn test_ranges() {
let mut bytes_input = BytesInput::new(vec![1, 2, 3]);
assert_eq!(bytes_input.sub_input(..1).start_index(), 0);
assert_eq!(bytes_input.sub_input(1..=1).start_index(), 1);
assert_eq!(bytes_input.sub_input(..1).end_index(), 1);
assert_eq!(bytes_input.sub_input(..=1).end_index(), 2);
assert_eq!(bytes_input.sub_input(1..=1).end_index(), 2);
assert_eq!(bytes_input.sub_input(1..).end_index(), 3);
assert_eq!(bytes_input.sub_input(..3).end_index(), 3);
}
}

View File

@ -12,6 +12,9 @@ pub use gramatron::*;
pub mod generalized; pub mod generalized;
pub use generalized::*; pub use generalized::*;
pub mod bytessub;
pub use bytessub::BytesSubInput;
#[cfg(feature = "multipart_inputs")] #[cfg(feature = "multipart_inputs")]
pub mod multi; pub mod multi;
#[cfg(feature = "multipart_inputs")] #[cfg(feature = "multipart_inputs")]
@ -23,15 +26,15 @@ pub mod nautilus;
use alloc::{ use alloc::{
boxed::Box, boxed::Box,
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::{Drain, Splice, Vec},
}; };
use core::{clone::Clone, fmt::Debug, marker::PhantomData}; use core::{clone::Clone, fmt::Debug, marker::PhantomData, ops::RangeBounds};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::{fs::File, hash::Hash, io::Read, path::Path}; use std::{fs::File, hash::Hash, io::Read, path::Path};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use libafl_bolts::fs::write_file_atomic; use libafl_bolts::fs::write_file_atomic;
use libafl_bolts::{ownedref::OwnedSlice, Error}; use libafl_bolts::{ownedref::OwnedSlice, Error, HasLen};
#[cfg(feature = "nautilus")] #[cfg(feature = "nautilus")]
pub use nautilus::*; pub use nautilus::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -73,7 +76,7 @@ pub trait Input: Clone + Serialize + serde::de::DeserializeOwned + Debug {
P: AsRef<Path>, P: AsRef<Path>,
{ {
let mut file = File::open(path)?; let mut file = File::open(path)?;
let mut bytes: Vec<u8> = vec![]; let mut bytes = vec![];
file.read_to_end(&mut bytes)?; file.read_to_end(&mut bytes)?;
Ok(postcard::from_bytes(&bytes)?) Ok(postcard::from_bytes(&bytes)?)
} }
@ -127,12 +130,89 @@ pub trait HasTargetBytes {
fn target_bytes(&self) -> OwnedSlice<u8>; fn target_bytes(&self) -> OwnedSlice<u8>;
} }
/// Contains an internal bytes Vector /// Contains mutateable and resizable bytes
pub trait HasBytesVec { pub trait HasMutatorBytes: HasLen {
/// The internal bytes map /// The bytes
fn bytes(&self) -> &[u8]; fn bytes(&self) -> &[u8];
/// The internal bytes map (as mutable borrow)
fn bytes_mut(&mut self) -> &mut Vec<u8>; /// The bytes to mutate
fn bytes_mut(&mut self) -> &mut [u8];
/// Resize the mutator bytes to a given new size.
/// Use `value` to fill new slots in case the buffer grows.
/// See [`alloc::vec::Vec::splice`].
fn resize(&mut self, new_len: usize, value: u8);
/// Extends the given buffer with an iterator. See [`alloc::vec::Vec::extend`]
fn extend<'a, I: IntoIterator<Item = &'a u8>>(&mut self, iter: I);
/// Splices the given target bytes according to [`alloc::vec::Vec::splice`]'s rules
fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = u8>;
/// Drains the given target bytes according to [`alloc::vec::Vec::drain`]'s rules
fn drain<R>(&mut self, range: R) -> Drain<'_, u8>
where
R: RangeBounds<usize>;
/// Creates a [`BytesSubInput`] from this input, that can be used for local mutations.
fn sub_input<R>(&mut self, range: R) -> BytesSubInput<Self>
where
R: RangeBounds<usize>,
{
BytesSubInput::new(self, range)
}
}
/// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`].
#[derive(Debug)]
pub struct MutVecInput<'a>(&'a mut Vec<u8>);
impl<'a> From<&'a mut Vec<u8>> for MutVecInput<'a> {
fn from(value: &'a mut Vec<u8>) -> Self {
Self(value)
}
}
impl<'a> HasLen for MutVecInput<'a> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a> HasMutatorBytes for MutVecInput<'a> {
fn bytes(&self) -> &[u8] {
self.0
}
fn bytes_mut(&mut self) -> &mut [u8] {
self.0
}
fn resize(&mut self, new_len: usize, value: u8) {
self.0.resize(new_len, value);
}
fn extend<'b, I: IntoIterator<Item = &'b u8>>(&mut self, iter: I) {
self.0.extend(iter);
}
fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = u8>,
{
self.0.splice::<R, I>(range, replace_with)
}
fn drain<R>(&mut self, range: R) -> Drain<'_, u8>
where
R: RangeBounds<usize>,
{
self.0.drain(range)
}
} }
/// Defines the input type shared across traits of the type. /// Defines the input type shared across traits of the type.

View File

@ -1,4 +1,4 @@
//! Mutators mutate input during fuzzing. //! [`Mutator`]`s` mutate input during fuzzing.
pub mod scheduled; pub mod scheduled;
use core::fmt; use core::fmt;
@ -87,14 +87,14 @@ pub enum MutationResult {
Skipped, Skipped,
} }
/// A mutator takes input, and mutates it. /// A [`Mutator`] takes an input, and mutates it.
/// Simple as that. /// Simple as that.
pub trait Mutator<I, S>: Named { pub trait Mutator<I, S>: Named {
/// Mutate a given input /// Mutate a given input
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>; fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>;
/// Post-process given the outcome of the execution /// Post-process given the outcome of the execution
/// `new_corpus_idx` will be `Some` if a new `Testcase` was created this execution. /// `new_corpus_idx` will be `Some` if a new [`crate::corpus::Testcase`] was created this execution.
#[inline] #[inline]
fn post_exec( fn post_exec(
&mut self, &mut self,
@ -129,12 +129,12 @@ pub trait MultiMutator<I, S>: Named {
} }
} }
/// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. /// A `Tuple` of [`Mutator`]`s` that can execute multiple `Mutators` in a row.
pub trait MutatorsTuple<I, S>: HasLen { pub trait MutatorsTuple<I, S>: HasLen {
/// Runs the `mutate` function on all `Mutators` in this `Tuple`. /// Runs the [`Mutator::mutate`] function on all [`Mutator`]`s` in this `Tuple`.
fn mutate_all(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>; fn mutate_all(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error>;
/// Runs the `post_exec` function on all `Mutators` in this `Tuple`. /// Runs the [`Mutator::post_exec`] function on all [`Mutator`]`s` in this `Tuple`.
/// `new_corpus_idx` will be `Some` if a new `Testcase` was created this execution. /// `new_corpus_idx` will be `Some` if a new `Testcase` was created this execution.
fn post_exec_all( fn post_exec_all(
&mut self, &mut self,

View File

@ -7,7 +7,7 @@ use libafl_bolts::{rands::Rand, Error};
use crate::{ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
impl_default_multipart, impl_default_multipart,
inputs::{multi::MultipartInput, HasBytesVec, Input}, inputs::{multi::MultipartInput, HasMutatorBytes, Input},
mutators::{ mutators::{
mutations::{ mutations::{
rand_range, BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator, rand_range, BitFlipMutator, ByteAddMutator, ByteDecMutator, ByteFlipMutator,
@ -117,7 +117,7 @@ impl_default_multipart!(
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverInsertMutator<I> impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverInsertMutator<I>
where where
S: HasCorpus<Input = MultipartInput<I>> + HasMaxSize + HasRand, S: HasCorpus<Input = MultipartInput<I>> + HasMaxSize + HasRand,
I: Input + HasBytesVec, I: Input + HasMutatorBytes,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -221,7 +221,7 @@ where
impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverReplaceMutator<I> impl<I, S> Mutator<MultipartInput<I>, S> for CrossoverReplaceMutator<I>
where where
S: HasCorpus<Input = MultipartInput<I>> + HasMaxSize + HasRand, S: HasCorpus<Input = MultipartInput<I>> + HasMaxSize + HasRand,
I: Input + HasBytesVec, I: Input + HasMutatorBytes,
{ {
fn mutate( fn mutate(
&mut self, &mut self,

View File

@ -10,7 +10,7 @@ use libafl_bolts::{rands::Rand, Named};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
inputs::{HasBytesVec, Input}, inputs::HasMutatorBytes,
mutators::{MutationResult, Mutator}, mutators::{MutationResult, Mutator},
random_corpus_id_with_disabled, random_corpus_id_with_disabled,
state::{HasCorpus, HasMaxSize, HasRand}, state::{HasCorpus, HasMaxSize, HasRand},
@ -123,7 +123,7 @@ pub struct BitFlipMutator;
impl<I, S> Mutator<I, S> for BitFlipMutator impl<I, S> Mutator<I, S> for BitFlipMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -159,7 +159,7 @@ pub struct ByteFlipMutator;
impl<I, S> Mutator<I, S> for ByteFlipMutator impl<I, S> Mutator<I, S> for ByteFlipMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -193,7 +193,7 @@ pub struct ByteIncMutator;
impl<I, S> Mutator<I, S> for ByteIncMutator impl<I, S> Mutator<I, S> for ByteIncMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -228,7 +228,7 @@ pub struct ByteDecMutator;
impl<I, S> Mutator<I, S> for ByteDecMutator impl<I, S> Mutator<I, S> for ByteDecMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -263,7 +263,7 @@ pub struct ByteNegMutator;
impl<I, S> Mutator<I, S> for ByteNegMutator impl<I, S> Mutator<I, S> for ByteNegMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -298,7 +298,7 @@ pub struct ByteRandMutator;
impl<I, S> Mutator<I, S> for ByteRandMutator impl<I, S> Mutator<I, S> for ByteRandMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
if input.bytes().is_empty() { if input.bytes().is_empty() {
@ -338,7 +338,7 @@ macro_rules! add_mutator_impl {
impl<I, S> Mutator<I, S> for $name impl<I, S> Mutator<I, S> for $name
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate( fn mutate(
&mut self, &mut self,
@ -405,7 +405,7 @@ macro_rules! interesting_mutator_impl {
impl<I, S> Mutator<I, S> for $name impl<I, S> Mutator<I, S> for $name
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
@ -454,7 +454,7 @@ pub struct BytesDeleteMutator;
impl<I, S> Mutator<I, S> for BytesDeleteMutator impl<I, S> Mutator<I, S> for BytesDeleteMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -464,7 +464,7 @@ where
let range = rand_range(state, size, size - 1); let range = rand_range(state, size, size - 1);
input.bytes_mut().drain(range); input.drain(range);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
@ -492,7 +492,7 @@ pub struct BytesExpandMutator;
impl<I, S> Mutator<I, S> for BytesExpandMutator impl<I, S> Mutator<I, S> for BytesExpandMutator
where where
S: HasRand + HasMaxSize, S: HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -503,7 +503,7 @@ where
let range = rand_range(state, size, min(16, max_size - size)); let range = rand_range(state, size, min(16, max_size - size));
input.bytes_mut().resize(size + range.len(), 0); input.resize(size + range.len(), 0);
unsafe { unsafe {
buffer_self_copy( buffer_self_copy(
input.bytes_mut(), input.bytes_mut(),
@ -539,7 +539,7 @@ pub struct BytesInsertMutator;
impl<I, S> Mutator<I, S> for BytesInsertMutator impl<I, S> Mutator<I, S> for BytesInsertMutator
where where
S: HasRand + HasMaxSize, S: HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -561,7 +561,7 @@ where
let val = input.bytes()[state.rand_mut().below(size)]; let val = input.bytes()[state.rand_mut().below(size)];
input.bytes_mut().resize(size + amount, 0); input.resize(size + amount, 0);
unsafe { unsafe {
buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset); buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
} }
@ -593,7 +593,7 @@ pub struct BytesRandInsertMutator;
impl<I, S> Mutator<I, S> for BytesRandInsertMutator impl<I, S> Mutator<I, S> for BytesRandInsertMutator
where where
S: HasRand + HasMaxSize, S: HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -615,7 +615,7 @@ where
let val = state.rand_mut().next() as u8; let val = state.rand_mut().next() as u8;
input.bytes_mut().resize(size + amount, 0); input.resize(size + amount, 0);
unsafe { unsafe {
buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset); buffer_self_copy(input.bytes_mut(), offset, offset + amount, size - offset);
} }
@ -647,7 +647,7 @@ pub struct BytesSetMutator;
impl<I, S> Mutator<I, S> for BytesSetMutator impl<I, S> Mutator<I, S> for BytesSetMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -686,7 +686,7 @@ pub struct BytesRandSetMutator;
impl<I, S> Mutator<I, S> for BytesRandSetMutator impl<I, S> Mutator<I, S> for BytesRandSetMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -725,7 +725,7 @@ pub struct BytesCopyMutator;
impl<I, S> Mutator<I, S> for BytesCopyMutator impl<I, S> Mutator<I, S> for BytesCopyMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -768,7 +768,7 @@ pub struct BytesInsertCopyMutator {
impl<I, S> Mutator<I, S> for BytesInsertCopyMutator impl<I, S> Mutator<I, S> for BytesInsertCopyMutator
where where
S: HasRand + HasMaxSize, S: HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -781,7 +781,7 @@ where
let max_insert_len = min(size - target, state.max_size() - size); let max_insert_len = min(size - target, state.max_size() - size);
let range = rand_range(state, size, min(16, max_insert_len)); let range = rand_range(state, size, min(16, max_insert_len));
input.bytes_mut().resize(size + range.len(), 0); input.resize(size + range.len(), 0);
self.tmp_buf.resize(range.len(), 0); self.tmp_buf.resize(range.len(), 0);
unsafe { unsafe {
buffer_copy( buffer_copy(
@ -829,7 +829,7 @@ pub struct BytesSwapMutator {
impl<I, S> Mutator<I, S> for BytesSwapMutator impl<I, S> Mutator<I, S> for BytesSwapMutator
where where
S: HasRand, S: HasRand,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -1029,15 +1029,15 @@ pub struct CrossoverInsertMutator<I> {
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<I: HasBytesVec> CrossoverInsertMutator<I> { impl<I: HasMutatorBytes> CrossoverInsertMutator<I> {
pub(crate) fn crossover_insert( pub(crate) fn crossover_insert<I2: HasMutatorBytes>(
input: &mut I, input: &mut I,
size: usize, size: usize,
target: usize, target: usize,
range: Range<usize>, range: Range<usize>,
other: &I, other: &I2,
) -> MutationResult { ) -> MutationResult {
input.bytes_mut().resize(size + range.len(), 0); input.resize(size + range.len(), 0);
unsafe { unsafe {
buffer_self_copy( buffer_self_copy(
input.bytes_mut(), input.bytes_mut(),
@ -1062,10 +1062,11 @@ impl<I: HasBytesVec> CrossoverInsertMutator<I> {
impl<I, S> Mutator<I, S> for CrossoverInsertMutator<I> impl<I, S> Mutator<I, S> for CrossoverInsertMutator<I>
where where
S: HasCorpus<Input = I> + HasRand + HasMaxSize, S: HasCorpus + HasRand + HasMaxSize,
I: Input + HasBytesVec, S::Input: HasMutatorBytes,
I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut S::Input) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
let max_size = state.max_size(); let max_size = state.max_size();
if size >= max_size { if size >= max_size {
@ -1124,12 +1125,12 @@ pub struct CrossoverReplaceMutator<I> {
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<I: HasBytesVec> CrossoverReplaceMutator<I> { impl<I: HasMutatorBytes> CrossoverReplaceMutator<I> {
pub(crate) fn crossover_replace( pub(crate) fn crossover_replace<I2: HasMutatorBytes>(
input: &mut I, input: &mut I,
target: usize, target: usize,
range: Range<usize>, range: Range<usize>,
other: &I, other: &I2,
) -> MutationResult { ) -> MutationResult {
unsafe { unsafe {
buffer_copy( buffer_copy(
@ -1146,10 +1147,11 @@ impl<I: HasBytesVec> CrossoverReplaceMutator<I> {
impl<I, S> Mutator<I, S> for CrossoverReplaceMutator<I> impl<I, S> Mutator<I, S> for CrossoverReplaceMutator<I>
where where
S: HasCorpus<Input = I> + HasRand, S: HasCorpus + HasRand,
I: Input + HasBytesVec, S::Input: HasMutatorBytes,
I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut S::Input) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
if size == 0 { if size == 0 {
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
@ -1224,7 +1226,7 @@ pub struct SpliceMutator;
impl<S> Mutator<S::Input, S> for SpliceMutator impl<S> Mutator<S::Input, S> for SpliceMutator
where where
S: HasCorpus + HasRand, S: HasCorpus + HasRand,
S::Input: HasBytesVec, S::Input: HasMutatorBytes,
{ {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
fn mutate(&mut self, state: &mut S, input: &mut S::Input) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut S::Input) -> Result<MutationResult, Error> {
@ -1255,9 +1257,7 @@ where
// Input will already be loaded. // Input will already be loaded.
let other = other_testcase.input().as_ref().unwrap(); let other = other_testcase.input().as_ref().unwrap();
input input.splice(split_at.., other.bytes()[split_at..].iter().copied());
.bytes_mut()
.splice(split_at.., other.bytes()[split_at..].iter().copied());
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }

View File

@ -480,7 +480,7 @@ mod tests {
use crate::{ use crate::{
corpus::{Corpus, InMemoryCorpus, Testcase}, corpus::{Corpus, InMemoryCorpus, Testcase},
feedbacks::ConstFeedback, feedbacks::ConstFeedback,
inputs::{BytesInput, HasBytesVec}, inputs::{BytesInput, HasMutatorBytes},
mutators::{ mutators::{
mutations::SpliceMutator, mutations::SpliceMutator,
scheduled::{havoc_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, StdScheduledMutator},

View File

@ -9,7 +9,7 @@ use libafl_bolts::{rands::Rand, Error, HasLen, Named};
use crate::{ use crate::{
corpus::{CorpusId, HasTestcase, Testcase}, corpus::{CorpusId, HasTestcase, Testcase},
inputs::{BytesInput, HasBytesVec}, inputs::{BytesInput, HasMutatorBytes},
mutators::{rand_range, MutationResult, Mutator, Tokens}, mutators::{rand_range, MutationResult, Mutator, Tokens},
stages::{ stages::{
extract_metadata, extract_metadata,
@ -259,7 +259,7 @@ fn rand_replace_range<S: HasRand + HasMaxSize, F: Fn(&mut S) -> char>(
} }
} }
input.0.bytes_mut().splice(range, replacement); input.0.splice(range, replacement);
input.1 = extract_metadata(input.0.bytes()); input.1 = extract_metadata(input.0.bytes());
MutationResult::Mutated MutationResult::Mutated
@ -423,7 +423,7 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
input.0.bytes_mut().splice(range, token.iter().copied()); input.0.splice(range, token.iter().copied());
input.1 = extract_metadata(input.0.bytes()); input.1 = extract_metadata(input.0.bytes());
return Ok(MutationResult::Mutated); return Ok(MutationResult::Mutated);
} }
@ -483,7 +483,7 @@ where
return Ok(MutationResult::Skipped); return Ok(MutationResult::Skipped);
} }
input.0.bytes_mut().splice(range, token.iter().copied()); input.0.splice(range, token.iter().copied());
input.1 = extract_metadata(input.0.bytes()); input.1 = extract_metadata(input.0.bytes());
return Ok(MutationResult::Mutated); return Ok(MutationResult::Mutated);
} }
@ -498,7 +498,7 @@ mod test {
use crate::{ use crate::{
corpus::NopCorpus, corpus::NopCorpus,
inputs::{BytesInput, HasBytesVec}, inputs::{BytesInput, HasMutatorBytes},
mutators::{Mutator, StringCategoryRandMutator, StringSubcategoryRandMutator}, mutators::{Mutator, StringCategoryRandMutator, StringSubcategoryRandMutator},
stages::extract_metadata, stages::extract_metadata,
state::StdState, state::StdState,

View File

@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
use crate::mutators::str_decode; use crate::mutators::str_decode;
use crate::{ use crate::{
corpus::{CorpusId, HasCurrentCorpusId}, corpus::{CorpusId, HasCurrentCorpusId},
inputs::{HasBytesVec, UsesInput}, inputs::{HasMutatorBytes, UsesInput},
mutators::{ mutators::{
buffer_self_copy, mutations::buffer_copy, MultiMutator, MutationResult, Mutator, Named, buffer_self_copy, mutations::buffer_copy, MultiMutator, MutationResult, Mutator, Named,
}, },
@ -305,7 +305,7 @@ pub struct TokenInsert;
impl<I, S> Mutator<I, S> for TokenInsert impl<I, S> Mutator<I, S> for TokenInsert
where where
S: HasMetadata + HasRand + HasMaxSize, S: HasMetadata + HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let max_size = state.max_size(); let max_size = state.max_size();
@ -335,7 +335,7 @@ where
} }
} }
input.bytes_mut().resize(size + len, 0); input.resize(size + len, 0);
unsafe { unsafe {
buffer_self_copy(input.bytes_mut(), off, off + len, size - off); buffer_self_copy(input.bytes_mut(), off, off + len, size - off);
buffer_copy(input.bytes_mut(), token, 0, off, len); buffer_copy(input.bytes_mut(), token, 0, off, len);
@ -368,7 +368,7 @@ pub struct TokenReplace;
impl<I, S> Mutator<I, S> for TokenReplace impl<I, S> Mutator<I, S> for TokenReplace
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
let size = input.bytes().len(); let size = input.bytes().len();
@ -427,7 +427,7 @@ pub struct I2SRandReplace;
impl<I, S> Mutator<I, S> for I2SRandReplace impl<I, S> Mutator<I, S> for I2SRandReplace
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize, S: UsesInput + HasMetadata + HasRand + HasMaxSize,
I: HasBytesVec, I: HasMutatorBytes,
{ {
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result<MutationResult, Error> {
@ -1088,7 +1088,7 @@ impl AFLppRedQueen {
impl<I, S> MultiMutator<I, S> for AFLppRedQueen impl<I, S> MultiMutator<I, S> for AFLppRedQueen
where where
S: UsesInput + HasMetadata + HasRand + HasMaxSize + HasCorpus + HasCurrentCorpusId, S: UsesInput + HasMetadata + HasRand + HasMaxSize + HasCorpus + HasCurrentCorpusId,
I: HasBytesVec + From<Vec<u8>>, I: HasMutatorBytes + From<Vec<u8>>,
{ {
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]

View File

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
events::EventFirer, events::EventFirer,
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
inputs::HasBytesVec, inputs::HasMutatorBytes,
mutators::mutations::buffer_copy, mutators::mutations::buffer_copy,
observers::{MapObserver, ObserversTuple}, observers::{MapObserver, ObserversTuple},
stages::{RetryRestartHelper, Stage}, stages::{RetryRestartHelper, Stage},
@ -84,7 +84,7 @@ where
EM: UsesState<State = E::State> + EventFirer, EM: UsesState<State = E::State> + EventFirer,
E: HasObservers + Executor<EM, Z>, E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata, E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata,
E::Input: HasBytesVec, E::Input: HasMutatorBytes,
O: MapObserver, O: MapObserver,
C: AsRef<O> + Named, C: AsRef<O> + Named,
Z: UsesState<State = E::State>, Z: UsesState<State = E::State>,
@ -161,7 +161,7 @@ where
C: AsRef<O> + Named, C: AsRef<O> + Named,
E: HasObservers + Executor<EM, Z>, E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand, E::State: HasCorpus + HasMetadata + HasRand,
E::Input: HasBytesVec, E::Input: HasMutatorBytes,
Z: UsesState<State = E::State>, Z: UsesState<State = E::State>,
{ {
#[inline] #[inline]

View File

@ -26,7 +26,7 @@ use crate::{
}; };
#[cfg(feature = "concolic_mutation")] #[cfg(feature = "concolic_mutation")]
use crate::{ use crate::{
inputs::HasBytesVec, inputs::HasMutatorBytes,
mark_feature_time, mark_feature_time,
observers::concolic::{ConcolicMetadata, SymExpr, SymExprRef}, observers::concolic::{ConcolicMetadata, SymExpr, SymExprRef},
stages::ExecutionCountRestartHelper, stages::ExecutionCountRestartHelper,
@ -372,7 +372,7 @@ where
E: UsesState<State = Z::State>, E: UsesState<State = Z::State>,
EM: UsesState<State = Z::State>, EM: UsesState<State = Z::State>,
Z: Evaluator<E, EM>, Z: Evaluator<E, EM>,
Z::Input: HasBytesVec, Z::Input: HasMutatorBytes,
Z::State: State + HasExecutions + HasCorpus + HasMetadata, Z::State: State + HasExecutions + HasCorpus + HasMetadata,
{ {
#[inline] #[inline]

View File

@ -12,7 +12,7 @@ use crate::{
corpus::{Corpus, HasCurrentCorpusId}, corpus::{Corpus, HasCurrentCorpusId},
executors::{Executor, HasObservers}, executors::{Executor, HasObservers},
feedbacks::map::MapNoveltiesMetadata, feedbacks::map::MapNoveltiesMetadata,
inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput}, inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasMutatorBytes, UsesInput},
mark_feature_time, mark_feature_time,
observers::{CanTrack, MapObserver, ObserversTuple}, observers::{CanTrack, MapObserver, ObserversTuple},
require_novelties_tracking, require_novelties_tracking,
@ -416,12 +416,8 @@ where
end = payload.len(); end = payload.len();
} }
let mut candidate = BytesInput::new(vec![]); let mut candidate = BytesInput::new(vec![]);
candidate candidate.extend(payload[..start].iter().flatten());
.bytes_mut() candidate.extend(payload[end..].iter().flatten());
.extend(payload[..start].iter().flatten());
candidate
.bytes_mut()
.extend(payload[end..].iter().flatten());
if self.verify_input(fuzzer, executor, state, manager, novelties, &candidate)? { if self.verify_input(fuzzer, executor, state, manager, novelties, &candidate)? {
for item in &mut payload[start..end] { for item in &mut payload[start..end] {
@ -469,12 +465,8 @@ where
if payload[end] == Some(closing_char) { if payload[end] == Some(closing_char) {
endings += 1; endings += 1;
let mut candidate = BytesInput::new(vec![]); let mut candidate = BytesInput::new(vec![]);
candidate candidate.extend(payload[..start].iter().flatten());
.bytes_mut() candidate.extend(payload[end..].iter().flatten());
.extend(payload[..start].iter().flatten());
candidate
.bytes_mut()
.extend(payload[end..].iter().flatten());
if self.verify_input(fuzzer, executor, state, manager, novelties, &candidate)? { if self.verify_input(fuzzer, executor, state, manager, novelties, &candidate)? {
for item in &mut payload[start..end] { for item in &mut payload[start..end] {

View File

@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
corpus::HasTestcase, corpus::HasTestcase,
inputs::{BytesInput, HasBytesVec}, inputs::{BytesInput, HasMutatorBytes},
stages::Stage, stages::Stage,
state::{HasCorpus, HasCurrentTestcase, State, UsesState}, state::{HasCorpus, HasCurrentTestcase, State, UsesState},
HasMetadata, HasMetadata,

View File

@ -1163,6 +1163,16 @@ impl<I> NopState<I> {
} }
} }
impl<I> HasMaxSize for NopState<I> {
fn max_size(&self) -> usize {
16_384
}
fn set_max_size(&mut self, _max_size: usize) {
unimplemented!("NopState doesn't allow setting a max size")
}
}
impl<I> UsesInput for NopState<I> impl<I> UsesInput for NopState<I>
where where
I: Input, I: Input,

View File

@ -8,7 +8,7 @@ use libafl::{
events::SimpleEventManager, events::SimpleEventManager,
executors::{inprocess_fork::InProcessForkExecutor, ExitKind}, executors::{inprocess_fork::InProcessForkExecutor, ExitKind},
feedbacks::{CrashFeedback, TimeoutFeedbackFactory}, feedbacks::{CrashFeedback, TimeoutFeedbackFactory},
inputs::{BytesInput, HasBytesVec, HasTargetBytes}, inputs::{BytesInput, HasMutatorBytes, HasTargetBytes},
mutators::{havoc_mutations_no_crossover, Mutator, StdScheduledMutator}, mutators::{havoc_mutations_no_crossover, Mutator, StdScheduledMutator},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::StdTMinMutationalStage, stages::StdTMinMutationalStage,

View File

@ -4,6 +4,8 @@ mod host_specific {
#[cfg(not(target_os = "linux"))] #[cfg(not(target_os = "linux"))]
pub fn build() { pub fn build() {
// Print a emulation_mode to silence clippy's unexpected cfg on macOS
println!("cargo:rustc-cfg=emulation_mode=\"usermode\"");
println!("cargo:warning=libafl_qemu only builds on Linux hosts"); println!("cargo:warning=libafl_qemu only builds on Linux hosts");
} }
} }

View File

@ -11,7 +11,7 @@ use std::{
use libafl::{ use libafl::{
corpus::Corpus, corpus::Corpus,
inputs::{BytesInput, HasBytesVec, UsesInput}, inputs::{BytesInput, HasMutatorBytes, UsesInput},
mutators::{ mutators::{
ComposedByMutations, MutationId, MutationResult, Mutator, MutatorsTuple, ScheduledMutator, ComposedByMutations, MutationId, MutationResult, Mutator, MutatorsTuple, ScheduledMutator,
}, },
@ -351,7 +351,7 @@ where
return result.replace(Ok(MutationResult::Skipped)); return result.replace(Ok(MutationResult::Skipped));
} }
bytes.truncate(new_size); bytes.truncate(new_size);
core::mem::swap(input.bytes_mut(), &mut bytes); input.bytes_mut().copy_from_slice(&bytes);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }
@ -440,7 +440,7 @@ where
return result.replace(Ok(MutationResult::Skipped)); return result.replace(Ok(MutationResult::Skipped));
} }
out.truncate(new_size); out.truncate(new_size);
core::mem::swap(input.bytes_mut(), &mut out); input.bytes_mut().copy_from_slice(&out);
Ok(MutationResult::Mutated) Ok(MutationResult::Mutated)
} }
} }