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:
parent
19ef29ed60
commit
684b31279e
@ -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(),
|
||||||
|
@ -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>
|
||||||
|
@ -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 {
|
||||||
|
426
libafl/src/inputs/bytessub.rs
Normal file
426
libafl/src/inputs/bytessub.rs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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},
|
||||||
|
@ -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,
|
||||||
|
@ -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)]
|
||||||
|
@ -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]
|
||||||
|
@ -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]
|
||||||
|
@ -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] {
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user