From 9672556fdb2939d6f48a34e798e2c97b8ef4784f Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 17:42:15 +0200 Subject: [PATCH 01/27] initial draft implementation --- libafl/src/inputs/bytes.rs | 11 +- libafl/src/inputs/bytessub.rs | 204 ++++++++++++++++++++++++++++------ libafl/src/inputs/mod.rs | 91 ++++++++++++++- libafl_bolts/src/ownedref.rs | 13 ++- 4 files changed, 273 insertions(+), 46 deletions(-) diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index 4fa9e0143b..4d5ab0e7f6 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -10,12 +10,12 @@ use core::{ use std::{fs::File, io::Read, path::Path}; use ahash::RandomState; +use libafl_bolts::HasLen; #[cfg(feature = "std")] use libafl_bolts::{fs::write_file_atomic, Error}; -use libafl_bolts::{ownedref::OwnedSlice, HasLen}; use serde::{Deserialize, Serialize}; -use crate::inputs::{HasMutatorBytes, HasTargetBytes, Input}; +use crate::inputs::{HasMutatorBytes, Input}; /// A bytes input is the basic input #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -96,13 +96,6 @@ impl HasMutatorBytes for BytesInput { } } -impl HasTargetBytes for BytesInput { - #[inline] - fn target_bytes(&self) -> OwnedSlice { - OwnedSlice::from(&self.bytes) - } -} - impl HasLen for BytesInput { #[inline] fn len(&self) -> usize { diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 262e7ff7dc..f7e169e10b 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -1,4 +1,4 @@ -//! [`BytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice +//! [`MutableBytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice use alloc::vec::Vec; use core::{ @@ -6,9 +6,9 @@ use core::{ ops::{Bound, Range, RangeBounds}, }; -use libafl_bolts::HasLen; +use libafl_bolts::{ownedref::OwnedSlice, HasLen}; -use super::HasMutatorBytes; +use super::{HasMutatorBytes, HasTargetBytes}; /// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) fn start_index(range: &R) -> usize @@ -27,14 +27,109 @@ fn end_index(range: &R, max_len: usize) -> usize where R: RangeBounds, { - match range.end_bound() { + let end = match range.end_bound() { Bound::Unbounded => max_len, Bound::Included(end) => end + 1, Bound::Excluded(end) => *end, + }; + + min(end, max_len) +} + +/// An immutable contiguous subslice of an input implementing [`HasTargetBytes`]. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// A mutable version is available: [`MutableBytesSubInput`]. +#[derive(Debug)] +pub struct BytesSubInput<'a> { + /// The (complete) parent input we will work on + parent_input: OwnedSlice<'a, u8>, + /// The range inside the parent input we will work on + range: Range, +} + +impl<'a> BytesSubInput<'a> { + /// Creates a new [`MutableBytesSubInput`] 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(parent_input: &'a I, range: R) -> Self + where + I: HasTargetBytes + HasLen, + R: RangeBounds, + { + let parent_len = parent_input.len(); + + let ret = BytesSubInput { + parent_input: parent_input.target_bytes(), + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + }; + + ret + } + + /// The parent input + pub fn parent_input(&self) -> OwnedSlice<'a, u8> { + self.parent_input.clone() + } + + /// The inclusive start index in the parent buffer + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R2) -> (Bound, Bound) + where + R2: RangeBounds, + { + 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) } } -/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on +/// The [`MutableBytesSubInput`] 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 @@ -48,7 +143,7 @@ where /// # 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..); +/// let mut sub_input = bytes_input.sub_input_mut(1..); /// /// // Run any mutations on the sub input. /// sub_input.bytes_mut()[0] = 42; @@ -74,7 +169,7 @@ where /// 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); +/// let mut sub_input = bytes_input.sub_input_mut(1..=3); /// /// assert_eq!(sub_input.bytes(), &[2, 3, 4]); /// @@ -85,11 +180,11 @@ where /// assert_eq!(bytes_input.bytes(), [1, 2, 3, 4, 42, 42, 42, 5]); /// ``` /// -/// The input supports all methods in the [`HasMutatorBytes`] trait. +/// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. #[derive(Debug)] -pub struct BytesSubInput<'a, I> +pub struct MutableBytesSubInput<'a, I> where - I: HasMutatorBytes + ?Sized, + I: HasTargetBytes + ?Sized, { /// The (complete) parent input we will work on pub(crate) parent_input: &'a mut I, @@ -97,11 +192,11 @@ where pub(crate) range: Range, } -impl<'a, I> BytesSubInput<'a, I> +impl<'a, I> MutableBytesSubInput<'a, I> where - I: HasMutatorBytes + ?Sized + HasLen, + I: HasTargetBytes + ?Sized + HasLen, { - /// Creates a new [`BytesSubInput`] that's a view on an input with mutator bytes. + /// Creates a new [`MutableBytesSubInput`] 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(parent_input: &'a mut I, range: R) -> Self where @@ -109,7 +204,7 @@ where { let parent_len = parent_input.len(); - BytesSubInput { + MutableBytesSubInput { parent_input, range: Range { start: start_index(&range), @@ -173,9 +268,9 @@ where } } -impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I> +impl<'a, I> HasMutatorBytes for MutableBytesSubInput<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasMutatorBytes, { #[inline] fn bytes(&self) -> &[u8] { @@ -272,13 +367,26 @@ where } } -impl<'a, I> HasLen for BytesSubInput<'a, I> +impl<'a> HasLen for BytesSubInput<'a> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a> HasTargetBytes for BytesSubInput<'a> { + fn target_bytes(&self) -> OwnedSlice { + self.parent_input.slice(self.range.clone()) + } +} + +impl<'a, I> HasLen for MutableBytesSubInput<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasTargetBytes + HasLen + ?Sized, { #[inline] fn len(&self) -> usize { - self.range.end - self.range.start + self.range.len() } } @@ -286,11 +394,12 @@ where mod tests { use alloc::vec::Vec; + use std::ops::Deref; use libafl_bolts::HasLen; use crate::{ - inputs::{BytesInput, HasMutatorBytes, MutVecInput, NopInput}, + inputs::{BytesInput, HasMutatorBytes, HasTargetBytes, MutVecInput, NopInput}, mutators::{havoc_mutations_no_crossover, MutatorsTuple}, state::NopState, }; @@ -303,19 +412,33 @@ mod tests { #[test] fn test_bytessubinput() { + let (bytes_input, _) = init_bytes_input(); + + let sub_input = bytes_input.sub_input(0..1); + assert_eq!(sub_input.target_bytes().deref(), &[1]); + + let sub_input = bytes_input.sub_input(1..=2); + assert_eq!(sub_input.target_bytes().deref(), &[2, 3]); + + let sub_input = bytes_input.sub_input(..); + assert_eq!(sub_input.target_bytes().deref(), &[1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_mutablebytessubinput() { let (mut bytes_input, len_orig) = init_bytes_input(); - let mut sub_input = bytes_input.sub_input(0..1); + let mut sub_input = bytes_input.sub_input_mut(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); + let mut sub_input = bytes_input.sub_input_mut(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(..); + let mut sub_input = bytes_input.sub_input_mut(..); assert_eq!(sub_input.len(), len_orig); sub_input.bytes_mut()[0] = 1; sub_input.bytes_mut()[1] = 2; @@ -327,7 +450,7 @@ mod tests { 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..); + let mut sub_input = bytes_input.sub_input_mut(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); @@ -337,25 +460,25 @@ mod tests { let (mut bytes_input, len_orig) = init_bytes_input(); - let mut sub_input = bytes_input.sub_input(..2); + let mut sub_input = bytes_input.sub_input_mut(..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); + let mut sub_input = bytes_input.sub_input_mut(..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); + let mut sub_input = bytes_input.sub_input_mut(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(..); + let mut sub_input = bytes_input.sub_input_mut(..); assert_eq!(sub_input.len(), bytes_input_orig.len()); sub_input.resize(1, 0); assert_eq!(sub_input.len(), 1); @@ -364,7 +487,7 @@ mod tests { assert_eq!(bytes_input.len(), 10); assert_eq!(bytes_input.bytes()[2], 0); - let mut sub_input = bytes_input.sub_input(..); + let mut sub_input = bytes_input.sub_input_mut(..); sub_input.resize(1, 0); assert_eq!(bytes_input.len(), 1); } @@ -374,12 +497,12 @@ mod tests { 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 mut sub_input = bytes_input.sub_input_mut(..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); + let mut sub_input = bytes_input.sub_input_mut(..0); assert_eq!(sub_input.len(), 0); let drained_len = drained.len(); sub_input.extend(&drained[..]); @@ -392,7 +515,7 @@ mod tests { 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 mut sub_input = bytes_input.sub_input_mut(..2); // Note that if you want to use NopState in production like this, you should see the rng! :) let mut state: NopState = NopState::new(); @@ -406,14 +529,14 @@ mod tests { 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); + let mut sub_vec = test_vec.sub_input_mut(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]); + let 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); @@ -423,4 +546,17 @@ mod tests { assert_eq!(bytes_input.sub_input(1..).end_index(), 3); assert_eq!(bytes_input.sub_input(..3).end_index(), 3); } + + #[test] + fn test_ranges_mut() { + let mut bytes_input = BytesInput::new(vec![1, 2, 3]); + + assert_eq!(bytes_input.sub_input_mut(..1).start_index(), 0); + assert_eq!(bytes_input.sub_input_mut(1..=1).start_index(), 1); + assert_eq!(bytes_input.sub_input_mut(..1).end_index(), 1); + assert_eq!(bytes_input.sub_input_mut(..=1).end_index(), 2); + assert_eq!(bytes_input.sub_input_mut(1..=1).end_index(), 2); + assert_eq!(bytes_input.sub_input_mut(1..).end_index(), 3); + assert_eq!(bytes_input.sub_input_mut(..3).end_index(), 3); + } } diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 6269a9b645..92b9e0676c 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::BytesSubInput; +pub use bytessub::{BytesSubInput, MutableBytesSubInput}; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -121,6 +121,48 @@ impl HasTargetBytes for NopInput { } } +/// Target bytes wrapper keeping track of the current read position. +/// Convenient wrapper when bytes must be split it in multiple subinputs. +#[derive(Debug)] +pub struct BytesReader<'a, I> +where + I: HasTargetBytes + HasLen, +{ + parent_input: &'a I, + pos: usize, +} + +impl<'a, I> BytesReader<'a, I> +where + I: HasTargetBytes + HasLen, +{ + /// Create a new [`BytesReader`]. + /// The position of the reader is initialized to 0. + pub fn new(input: &'a I) -> Self { + Self { + parent_input: input, + pos: 0, + } + } + + /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + #[must_use] + pub fn read_to_slice(&mut self, limit: usize) -> BytesSubInput<'a> { + let sub_input = BytesSubInput::new(self.parent_input, self.pos..(self.pos + limit)); + + self.pos += sub_input.len(); + + sub_input + } +} + +impl<'a, I: HasTargetBytes + HasLen> From<&'a I> for BytesReader<'a, I> { + fn from(input: &'a I) -> Self { + Self::new(input) + } +} + // TODO change this to fn target_bytes(&self, buffer: &mut Vec) -> &[u8]; /// Can be represented with a vector of bytes. /// This representation is not necessarily deserializable. @@ -158,12 +200,31 @@ pub trait HasMutatorBytes: HasLen { R: RangeBounds; /// Creates a [`BytesSubInput`] from this input, that can be used for local mutations. - fn sub_input(&mut self, range: R) -> BytesSubInput + fn sub_input(&self, range: R) -> BytesSubInput where R: RangeBounds, + Self: Sized, { BytesSubInput::new(self, range) } + + /// Creates a [`MutableBytesSubInput`] from this input, that can be used for local mutations. + fn sub_input_mut(&mut self, range: R) -> MutableBytesSubInput + where + R: RangeBounds, + Self: Sized, + { + MutableBytesSubInput::new(self, range) + } +} + +impl HasTargetBytes for I +where + I: HasMutatorBytes, +{ + fn target_bytes(&self) -> OwnedSlice { + OwnedSlice::from(self.bytes()) + } } /// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`]. @@ -292,3 +353,29 @@ where (self.convert_cb)(input) } } + +#[cfg(test)] +mod tests { + use std::ops::Deref; + + use crate::inputs::{BytesInput, BytesReader, HasTargetBytes}; + + #[test] + fn test_bytesreader() { + let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); + let mut bytes_reader = BytesReader::new(&bytes_input); + + let bytes_read = bytes_reader.read_to_slice(2); + assert_eq!(bytes_read.target_bytes().deref(), &[1, 2]); + + let bytes_read = bytes_reader.read_to_slice(3); + assert_eq!(bytes_read.target_bytes().deref(), &[3, 4, 5]); + + let bytes_read = bytes_reader.read_to_slice(8); + assert_eq!(bytes_read.target_bytes().deref(), &[6, 7]); + + let bytes_read = bytes_reader.read_to_slice(8); + let bytes_read_ref: &[u8] = &[]; + assert_eq!(bytes_read.target_bytes().deref(), bytes_read_ref); + } +} diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index 9cf4e19568..09efd69ba4 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -9,8 +9,9 @@ use alloc::{ use core::{ clone::Clone, fmt::Debug, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, RangeBounds}, slice, + slice::SliceIndex, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -407,6 +408,16 @@ impl<'a, T> OwnedSlice<'a, T> { pub fn iter(&self) -> Iter<'_, T> { <&Self as IntoIterator>::into_iter(self) } + + /// Returns a subslice of the slice. + pub fn slice + SliceIndex<[T], Output = [T]>>( + &'a self, + range: R, + ) -> OwnedSlice<'a, T> { + OwnedSlice { + inner: OwnedSliceInner::Ref(&self[range]), + } + } } impl<'a, 'it, T> IntoIterator for &'it OwnedSlice<'a, T> { From c22af4af3ac4202759f880ca9532756794a0b11e Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 17:46:49 +0200 Subject: [PATCH 02/27] change name to follow rust convention. --- libafl/src/inputs/bytessub.rs | 20 ++++++++++---------- libafl/src/inputs/mod.rs | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index f7e169e10b..e93c7f3416 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -1,4 +1,4 @@ -//! [`MutableBytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice +//! [`BytesSubInputMut`] is a wrapper input that can be used to mutate parts of a byte slice use alloc::vec::Vec; use core::{ @@ -39,7 +39,7 @@ where /// An immutable contiguous subslice of an input implementing [`HasTargetBytes`]. /// It is mostly useful to cheaply wrap a subslice of a given input. /// -/// A mutable version is available: [`MutableBytesSubInput`]. +/// A mutable version is available: [`BytesSubInputMut`]. #[derive(Debug)] pub struct BytesSubInput<'a> { /// The (complete) parent input we will work on @@ -49,7 +49,7 @@ pub struct BytesSubInput<'a> { } impl<'a> BytesSubInput<'a> { - /// Creates a new [`MutableBytesSubInput`] that's a view on an input with mutator bytes. + /// Creates a new [`BytesSubInputMut`] 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(parent_input: &'a I, range: R) -> Self where @@ -129,7 +129,7 @@ impl<'a> BytesSubInput<'a> { } } -/// The [`MutableBytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on +/// The [`BytesSubInputMut`] 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 @@ -182,7 +182,7 @@ impl<'a> BytesSubInput<'a> { /// /// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. #[derive(Debug)] -pub struct MutableBytesSubInput<'a, I> +pub struct BytesSubInputMut<'a, I> where I: HasTargetBytes + ?Sized, { @@ -192,11 +192,11 @@ where pub(crate) range: Range, } -impl<'a, I> MutableBytesSubInput<'a, I> +impl<'a, I> BytesSubInputMut<'a, I> where I: HasTargetBytes + ?Sized + HasLen, { - /// Creates a new [`MutableBytesSubInput`] that's a view on an input with mutator bytes. + /// Creates a new [`BytesSubInputMut`] 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(parent_input: &'a mut I, range: R) -> Self where @@ -204,7 +204,7 @@ where { let parent_len = parent_input.len(); - MutableBytesSubInput { + BytesSubInputMut { parent_input, range: Range { start: start_index(&range), @@ -268,7 +268,7 @@ where } } -impl<'a, I> HasMutatorBytes for MutableBytesSubInput<'a, I> +impl<'a, I> HasMutatorBytes for BytesSubInputMut<'a, I> where I: HasMutatorBytes, { @@ -380,7 +380,7 @@ impl<'a> HasTargetBytes for BytesSubInput<'a> { } } -impl<'a, I> HasLen for MutableBytesSubInput<'a, I> +impl<'a, I> HasLen for BytesSubInputMut<'a, I> where I: HasTargetBytes + HasLen + ?Sized, { diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 92b9e0676c..b38511c430 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::{BytesSubInput, MutableBytesSubInput}; +pub use bytessub::{BytesSubInput, BytesSubInputMut}; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -208,13 +208,13 @@ pub trait HasMutatorBytes: HasLen { BytesSubInput::new(self, range) } - /// Creates a [`MutableBytesSubInput`] from this input, that can be used for local mutations. - fn sub_input_mut(&mut self, range: R) -> MutableBytesSubInput + /// Creates a [`BytesSubInputMut`] from this input, that can be used for local mutations. + fn sub_input_mut(&mut self, range: R) -> BytesSubInputMut where R: RangeBounds, Self: Sized, { - MutableBytesSubInput::new(self, range) + BytesSubInputMut::new(self, range) } } From 75b45636e7b6a90c043efaf32e41850e2fbc4cfb Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 17:59:25 +0200 Subject: [PATCH 03/27] revert use of HasTargetBytes instead of HasMutatorBytes for BytesSubInputMut --- libafl/src/inputs/bytessub.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index e93c7f3416..d7f61cadbf 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -184,7 +184,7 @@ impl<'a> BytesSubInput<'a> { #[derive(Debug)] pub struct BytesSubInputMut<'a, I> where - I: HasTargetBytes + ?Sized, + I: HasMutatorBytes + ?Sized, { /// The (complete) parent input we will work on pub(crate) parent_input: &'a mut I, @@ -194,7 +194,7 @@ where impl<'a, I> BytesSubInputMut<'a, I> where - I: HasTargetBytes + ?Sized + HasLen, + I: HasMutatorBytes + ?Sized + HasLen, { /// Creates a new [`BytesSubInputMut`] that's a view on an input with mutator bytes. /// The sub input can then be used to mutate parts of the original input. @@ -382,7 +382,7 @@ impl<'a> HasTargetBytes for BytesSubInput<'a> { impl<'a, I> HasLen for BytesSubInputMut<'a, I> where - I: HasTargetBytes + HasLen + ?Sized, + I: HasMutatorBytes + HasLen + ?Sized, { #[inline] fn len(&self) -> usize { From 0557eb11555dd1e7d9ad9c54d469e9d6886d2d54 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 18:12:13 +0200 Subject: [PATCH 04/27] clippy --- libafl_bolts/src/ownedref.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index 09efd69ba4..b7eb24ed5f 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -410,6 +410,7 @@ impl<'a, T> OwnedSlice<'a, T> { } /// Returns a subslice of the slice. + #[must_use] pub fn slice + SliceIndex<[T], Output = [T]>>( &'a self, range: R, From ce49d429c50258923e63f77d3b3d71577fd7000c Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 18:13:40 +0200 Subject: [PATCH 05/27] nostd --- libafl/src/inputs/bytessub.rs | 2 +- libafl/src/inputs/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index d7f61cadbf..06a8d65140 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -394,7 +394,7 @@ where mod tests { use alloc::vec::Vec; - use std::ops::Deref; + use core::ops::Deref; use libafl_bolts::HasLen; diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index b38511c430..7d6749ab87 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -356,7 +356,7 @@ where #[cfg(test)] mod tests { - use std::ops::Deref; + use core::ops::Deref; use crate::inputs::{BytesInput, BytesReader, HasTargetBytes}; From 20ce3599006a5c2e106b0794a14d1b40797a3555 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 18:14:39 +0200 Subject: [PATCH 06/27] clippy --- libafl/src/inputs/bytessub.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 06a8d65140..ab09d95a2b 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -70,16 +70,19 @@ impl<'a> BytesSubInput<'a> { } /// The parent input + #[must_use] pub fn parent_input(&self) -> OwnedSlice<'a, u8> { self.parent_input.clone() } /// The inclusive start index in the parent buffer + #[must_use] pub fn start_index(&self) -> usize { self.range.start } /// The exclusive end index in the parent buffer + #[must_use] pub fn end_index(&self) -> usize { self.range.end } From caa6cacca8c487d842518975d27b25b73f21154f Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 29 May 2024 18:23:31 +0200 Subject: [PATCH 07/27] clippy --- libafl/src/inputs/bytessub.rs | 7 +++---- libafl/src/inputs/mod.rs | 10 ++++------ 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index ab09d95a2b..a760e99072 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -397,7 +397,6 @@ where mod tests { use alloc::vec::Vec; - use core::ops::Deref; use libafl_bolts::HasLen; @@ -418,13 +417,13 @@ mod tests { let (bytes_input, _) = init_bytes_input(); let sub_input = bytes_input.sub_input(0..1); - assert_eq!(sub_input.target_bytes().deref(), &[1]); + assert_eq!(*sub_input.target_bytes(), [1]); let sub_input = bytes_input.sub_input(1..=2); - assert_eq!(sub_input.target_bytes().deref(), &[2, 3]); + assert_eq!(*sub_input.target_bytes(), [2, 3]); let sub_input = bytes_input.sub_input(..); - assert_eq!(sub_input.target_bytes().deref(), &[1, 2, 3, 4, 5, 6, 7]); + assert_eq!(*sub_input.target_bytes(), [1, 2, 3, 4, 5, 6, 7]); } #[test] diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 7d6749ab87..04e8640c2d 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -356,8 +356,6 @@ where #[cfg(test)] mod tests { - use core::ops::Deref; - use crate::inputs::{BytesInput, BytesReader, HasTargetBytes}; #[test] @@ -366,16 +364,16 @@ mod tests { let mut bytes_reader = BytesReader::new(&bytes_input); let bytes_read = bytes_reader.read_to_slice(2); - assert_eq!(bytes_read.target_bytes().deref(), &[1, 2]); + assert_eq!(*bytes_read.target_bytes(), [1, 2]); let bytes_read = bytes_reader.read_to_slice(3); - assert_eq!(bytes_read.target_bytes().deref(), &[3, 4, 5]); + assert_eq!(*bytes_read.target_bytes(), [3, 4, 5]); let bytes_read = bytes_reader.read_to_slice(8); - assert_eq!(bytes_read.target_bytes().deref(), &[6, 7]); + assert_eq!(*bytes_read.target_bytes(), [6, 7]); let bytes_read = bytes_reader.read_to_slice(8); let bytes_read_ref: &[u8] = &[]; - assert_eq!(bytes_read.target_bytes().deref(), bytes_read_ref); + assert_eq!(&*bytes_read.target_bytes(), bytes_read_ref); } } From 0eb55b3f07dfa5528be892af288ea0c98ad475a2 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Thu, 30 May 2024 11:48:05 +0200 Subject: [PATCH 08/27] * HasLen required if implementing HasTargetBytes. * Added a checked version of the read to slice. --- libafl/src/inputs/mod.rs | 92 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 04e8640c2d..60ce6eb2fd 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -117,7 +117,13 @@ impl Input for NopInput { } impl HasTargetBytes for NopInput { fn target_bytes(&self) -> OwnedSlice { - OwnedSlice::from(vec![0]) + OwnedSlice::from(vec![]) + } +} + +impl HasLen for NopInput { + fn len(&self) -> usize { + 0 } } @@ -132,6 +138,35 @@ where pos: usize, } +/// Representation of a partial slice +/// This is used when providing a slice smaller than the expected one. +/// It notably happens when trying to read the end of an input. +#[derive(Debug)] +pub enum PartialBytesSubInput<'a> { + /// The slice is empty, and thus not kept + Empty, + /// The slice is strictly smaller than the expected one. + Partial(BytesSubInput<'a>), +} + +impl<'a> PartialBytesSubInput<'a> { + /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. + pub fn empty(self) -> bool { + match self { + PartialBytesSubInput::Empty => true, + _ => false, + } + } + + /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. + pub fn partial(self) -> Option> { + match self { + PartialBytesSubInput::Partial(partial_slice) => Some(partial_slice), + _ => None, + } + } +} + impl<'a, I> BytesReader<'a, I> where I: HasTargetBytes + HasLen, @@ -147,14 +182,34 @@ where /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + /// This function does not provide any feedback on whether the slice was cropped or not. #[must_use] - pub fn read_to_slice(&mut self, limit: usize) -> BytesSubInput<'a> { + pub fn read_to_slice_unchecked(&mut self, limit: usize) -> BytesSubInput<'a> { let sub_input = BytesSubInput::new(self.parent_input, self.pos..(self.pos + limit)); self.pos += sub_input.len(); sub_input } + + /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + pub fn read_to_slice( + &mut self, + limit: usize, + ) -> Result, PartialBytesSubInput<'a>> { + let slice_to_return = self.read_to_slice_unchecked(limit); + + let real_len = slice_to_return.len(); + + if real_len == 0 { + Err(PartialBytesSubInput::Empty) + } else if real_len < limit { + Err(PartialBytesSubInput::Partial(slice_to_return)) + } else { + Ok(slice_to_return) + } + } } impl<'a, I: HasTargetBytes + HasLen> From<&'a I> for BytesReader<'a, I> { @@ -167,7 +222,7 @@ impl<'a, I: HasTargetBytes + HasLen> From<&'a I> for BytesReader<'a, I> { /// Can be represented with a vector of bytes. /// This representation is not necessarily deserializable. /// Instead, it can be used as bytes input for a target -pub trait HasTargetBytes { +pub trait HasTargetBytes: HasLen { /// Target bytes, that can be written to a target fn target_bytes(&self) -> OwnedSlice; } @@ -359,21 +414,42 @@ mod tests { use crate::inputs::{BytesInput, BytesReader, HasTargetBytes}; #[test] - fn test_bytesreader() { + fn test_bytesreader_toslice_unchecked() { let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); let mut bytes_reader = BytesReader::new(&bytes_input); - let bytes_read = bytes_reader.read_to_slice(2); + let bytes_read = bytes_reader.read_to_slice_unchecked(2); assert_eq!(*bytes_read.target_bytes(), [1, 2]); - let bytes_read = bytes_reader.read_to_slice(3); + let bytes_read = bytes_reader.read_to_slice_unchecked(3); assert_eq!(*bytes_read.target_bytes(), [3, 4, 5]); - let bytes_read = bytes_reader.read_to_slice(8); + let bytes_read = bytes_reader.read_to_slice_unchecked(8); assert_eq!(*bytes_read.target_bytes(), [6, 7]); - let bytes_read = bytes_reader.read_to_slice(8); + let bytes_read = bytes_reader.read_to_slice_unchecked(8); let bytes_read_ref: &[u8] = &[]; assert_eq!(&*bytes_read.target_bytes(), bytes_read_ref); } + + #[test] + fn test_bytesreader_toslice() { + let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); + let mut bytes_reader = BytesReader::new(&bytes_input); + + let bytes_read = bytes_reader.read_to_slice(2); + assert_eq!(*bytes_read.unwrap().target_bytes(), [1, 2]); + + let bytes_read = bytes_reader.read_to_slice(3); + assert_eq!(*bytes_read.unwrap().target_bytes(), [3, 4, 5]); + + let bytes_read = bytes_reader.read_to_slice(8); + assert_eq!( + *bytes_read.unwrap_err().partial().unwrap().target_bytes(), + [6, 7] + ); + + let bytes_read = bytes_reader.read_to_slice(8); + assert!(bytes_read.unwrap_err().empty()); + } } From 050622c52576510cb8442bda0eca97efb4a525ea Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Thu, 30 May 2024 11:52:51 +0200 Subject: [PATCH 09/27] clippy --- libafl/src/inputs/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 60ce6eb2fd..63b669a7e1 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -151,15 +151,15 @@ pub enum PartialBytesSubInput<'a> { impl<'a> PartialBytesSubInput<'a> { /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. + #[must_use] pub fn empty(self) -> bool { - match self { - PartialBytesSubInput::Empty => true, - _ => false, - } + matches!(self, PartialBytesSubInput::Empty) } /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. + #[must_use] pub fn partial(self) -> Option> { + #[allow(clippy::match_wildcard_for_single_variants)] match self { PartialBytesSubInput::Partial(partial_slice) => Some(partial_slice), _ => None, From 38a79416a846e25ed604a0137dbaf6de61f77c67 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 3 Jun 2024 13:36:55 +0200 Subject: [PATCH 10/27] fix name. better doc. --- libafl/src/inputs/mod.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 63b669a7e1..e29e337df5 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -181,10 +181,10 @@ where } /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. - /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. /// This function does not provide any feedback on whether the slice was cropped or not. #[must_use] - pub fn read_to_slice_unchecked(&mut self, limit: usize) -> BytesSubInput<'a> { + pub fn read_to_slice_truncated(&mut self, limit: usize) -> BytesSubInput<'a> { let sub_input = BytesSubInput::new(self.parent_input, self.pos..(self.pos + limit)); self.pos += sub_input.len(); @@ -194,11 +194,15 @@ where /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + /// The function returns + /// - `Ok(Slice)` if the returned slice has `limit` bytes. + /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` bytes and is not empty. + /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. pub fn read_to_slice( &mut self, limit: usize, ) -> Result, PartialBytesSubInput<'a>> { - let slice_to_return = self.read_to_slice_unchecked(limit); + let slice_to_return = self.read_to_slice_truncated(limit); let real_len = slice_to_return.len(); @@ -418,16 +422,16 @@ mod tests { let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); let mut bytes_reader = BytesReader::new(&bytes_input); - let bytes_read = bytes_reader.read_to_slice_unchecked(2); + let bytes_read = bytes_reader.read_to_slice_truncated(2); assert_eq!(*bytes_read.target_bytes(), [1, 2]); - let bytes_read = bytes_reader.read_to_slice_unchecked(3); + let bytes_read = bytes_reader.read_to_slice_truncated(3); assert_eq!(*bytes_read.target_bytes(), [3, 4, 5]); - let bytes_read = bytes_reader.read_to_slice_unchecked(8); + let bytes_read = bytes_reader.read_to_slice_truncated(8); assert_eq!(*bytes_read.target_bytes(), [6, 7]); - let bytes_read = bytes_reader.read_to_slice_unchecked(8); + let bytes_read = bytes_reader.read_to_slice_truncated(8); let bytes_read_ref: &[u8] = &[]; assert_eq!(&*bytes_read.target_bytes(), bytes_read_ref); } From e86ca6ac58991f5e21287582d6fcf2f1702191bc Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 3 Jul 2024 10:31:41 +0200 Subject: [PATCH 11/27] added a common bytes trait for HasTargetBytes and HasMutatorBytes. --- libafl/src/inputs/bytes.rs | 31 +++++--- libafl/src/inputs/bytessub.rs | 62 ++++++++------- libafl/src/inputs/mod.rs | 77 ++++++++++--------- libafl/src/mutators/multi.rs | 16 ++-- libafl/src/mutators/mutations.rs | 66 ++++++++-------- libafl/src/mutators/scheduled.rs | 4 +- libafl/src/mutators/token_mutations.rs | 18 ++--- libafl/src/mutators/unicode/mod.rs | 34 ++++---- libafl/src/stages/colorization.rs | 8 +- libafl/src/stages/generalization.rs | 2 +- libafl/src/stages/unicode.rs | 2 +- libafl_bolts/src/lib.rs | 1 - .../libafl_libfuzzer_runtime/src/tmin.rs | 2 +- libafl_qemu/src/helpers/injections.rs | 3 +- libafl_targets/src/libfuzzer/mutators.rs | 8 +- utils/libafl_benches/benches/hash_speeds.rs | 9 +-- 16 files changed, 182 insertions(+), 161 deletions(-) diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index f127432923..21c49a0c67 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -10,14 +10,14 @@ use core::{ use std::{fs::File, io::Read, path::Path}; use ahash::RandomState; -use libafl_bolts::HasLen; #[cfg(feature = "std")] use libafl_bolts::{fs::write_file_atomic, Error}; +use libafl_bolts::{ownedref::OwnedSlice, HasLen}; use serde::{Deserialize, Serialize}; use crate::{ corpus::CorpusId, - inputs::{HasMutatorBytes, HasTargetBytes, Input}, + inputs::{HasBytes, HasMutatorBytes, HasTargetBytes, Input}, }; /// A bytes input is the basic input @@ -52,7 +52,7 @@ impl Input for BytesInput { /// Generate a name for this input fn generate_name(&self, _id: Option) -> String { let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); - hasher.write(self.bytes()); + hasher.write(self.bytes_ref()); format!("{:016x}", hasher.finish()) } } @@ -64,9 +64,25 @@ impl From for Rc> { } } +impl HasLen for BytesInput { + #[inline] + fn len(&self) -> usize { + self.bytes.len() + } +} + +impl HasBytes for BytesInput { + #[inline] + fn bytes(&self) -> OwnedSlice { + OwnedSlice::from(&self.bytes) + } +} + +impl HasTargetBytes for BytesInput {} + impl HasMutatorBytes for BytesInput { #[inline] - fn bytes(&self) -> &[u8] { + fn bytes_ref(&self) -> &[u8] { &self.bytes } @@ -99,13 +115,6 @@ impl HasMutatorBytes for BytesInput { } } -impl HasLen for BytesInput { - #[inline] - fn len(&self) -> usize { - self.bytes.len() - } -} - impl From> for BytesInput { fn from(bytes: Vec) -> Self { Self::new(bytes) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index a760e99072..f95a6f04e3 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -8,7 +8,7 @@ use core::{ use libafl_bolts::{ownedref::OwnedSlice, HasLen}; -use super::{HasMutatorBytes, HasTargetBytes}; +use super::{HasBytes, HasMutatorBytes, HasTargetBytes}; /// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) fn start_index(range: &R) -> usize @@ -53,13 +53,13 @@ impl<'a> BytesSubInput<'a> { /// The sub input can then be used to mutate parts of the original input. pub fn new(parent_input: &'a I, range: R) -> Self where - I: HasTargetBytes + HasLen, + I: HasBytes, R: RangeBounds, { let parent_len = parent_input.len(); let ret = BytesSubInput { - parent_input: parent_input.target_bytes(), + parent_input: parent_input.bytes(), range: Range { start: start_index(&range), end: end_index(&range, parent_len), @@ -152,7 +152,7 @@ impl<'a> BytesSubInput<'a> { /// sub_input.bytes_mut()[0] = 42; /// /// // The mutations are applied to the underlying input. -/// assert_eq!(bytes_input.bytes()[1], 42); +/// assert_eq!(bytes_input.bytes_ref()[1], 42); /// ``` /// /// Growing or shrinking the sub input will grow or shrink the parent input, @@ -174,13 +174,13 @@ impl<'a> BytesSubInput<'a> { /// // Note that the range ends on an exclusive value this time. /// let mut sub_input = bytes_input.sub_input_mut(1..=3); /// -/// assert_eq!(sub_input.bytes(), &[2, 3, 4]); +/// assert_eq!(sub_input.bytes_ref(), &[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]); +/// assert_eq!(bytes_input.bytes_ref(), [1, 2, 3, 4, 42, 42, 42, 5]); /// ``` /// /// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. @@ -271,13 +271,31 @@ where } } +impl<'a, I> HasLen for BytesSubInputMut<'a, I> +where + I: HasMutatorBytes + ?Sized, +{ + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, I> HasBytes for BytesSubInputMut<'a, I> +where + I: HasMutatorBytes + ?Sized, +{ + fn bytes(&self) -> OwnedSlice { + (&self.parent_input.bytes_ref()[self.range.clone()]).into() + } +} + impl<'a, I> HasMutatorBytes for BytesSubInputMut<'a, I> where I: HasMutatorBytes, { #[inline] - fn bytes(&self) -> &[u8] { - &self.parent_input.bytes()[self.range.clone()] + fn bytes_ref(&self) -> &[u8] { + &self.parent_input.bytes_ref()[self.range.clone()] } #[inline] @@ -377,21 +395,13 @@ impl<'a> HasLen for BytesSubInput<'a> { } } -impl<'a> HasTargetBytes for BytesSubInput<'a> { - fn target_bytes(&self) -> OwnedSlice { +impl<'a> HasBytes for BytesSubInput<'a> { + fn bytes(&self) -> OwnedSlice { self.parent_input.slice(self.range.clone()) } } -impl<'a, I> HasLen for BytesSubInputMut<'a, I> -where - I: HasMutatorBytes + HasLen + ?Sized, -{ - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} +impl<'a> HasTargetBytes for BytesSubInput<'a> {} #[cfg(test)] mod tests { @@ -433,18 +443,18 @@ mod tests { let mut sub_input = bytes_input.sub_input_mut(0..1); assert_eq!(sub_input.len(), 1); sub_input.bytes_mut()[0] = 2; - assert_eq!(bytes_input.bytes()[0], 2); + assert_eq!(bytes_input.bytes_ref()[0], 2); let mut sub_input = bytes_input.sub_input_mut(1..=2); assert_eq!(sub_input.len(), 2); sub_input.bytes_mut()[0] = 3; - assert_eq!(bytes_input.bytes()[1], 3); + assert_eq!(bytes_input.bytes_ref()[1], 3); let mut sub_input = bytes_input.sub_input_mut(..); 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); + assert_eq!(bytes_input.bytes_ref()[0], 1); } #[test] @@ -455,10 +465,10 @@ mod tests { let mut sub_input = bytes_input.sub_input_mut(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.bytes_ref()[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); + assert_eq!(bytes_input.bytes_ref()[bytes_input.len() - 1], 0); let (mut bytes_input, len_orig) = init_bytes_input(); @@ -466,7 +476,7 @@ mod tests { 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!(sub_input.bytes_ref()[sub_input.len() - 1], 0); assert_eq!(bytes_input.len(), len_orig + 1); let mut sub_input = bytes_input.sub_input_mut(..3); @@ -487,7 +497,7 @@ mod tests { sub_input.resize(10, 0); assert_eq!(sub_input.len(), 10); assert_eq!(bytes_input.len(), 10); - assert_eq!(bytes_input.bytes()[2], 0); + assert_eq!(bytes_input.bytes_ref()[2], 0); let mut sub_input = bytes_input.sub_input_mut(..); sub_input.resize(1, 0); diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 01f4e8e9a8..92d6a247e0 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -117,12 +117,14 @@ impl Input for NopInput { "nop-input".to_string() } } -impl HasTargetBytes for NopInput { - fn target_bytes(&self) -> OwnedSlice { +impl HasBytes for NopInput { + fn bytes(&self) -> OwnedSlice { OwnedSlice::from(vec![]) } } +impl HasTargetBytes for NopInput {} + impl HasLen for NopInput { fn len(&self) -> usize { 0 @@ -132,10 +134,7 @@ impl HasLen for NopInput { /// Target bytes wrapper keeping track of the current read position. /// Convenient wrapper when bytes must be split it in multiple subinputs. #[derive(Debug)] -pub struct BytesReader<'a, I> -where - I: HasTargetBytes + HasLen, -{ +pub struct BytesReader<'a, I> { parent_input: &'a I, pos: usize, } @@ -186,7 +185,7 @@ where /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. /// This function does not provide any feedback on whether the slice was cropped or not. #[must_use] - pub fn read_to_slice_truncated(&mut self, limit: usize) -> BytesSubInput<'a> { + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> BytesSubInput<'a> { let sub_input = BytesSubInput::new(self.parent_input, self.pos..(self.pos + limit)); self.pos += sub_input.len(); @@ -200,11 +199,11 @@ where /// - `Ok(Slice)` if the returned slice has `limit` bytes. /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` bytes and is not empty. /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. - pub fn read_to_slice( + pub fn next_sub_input( &mut self, limit: usize, ) -> Result, PartialBytesSubInput<'a>> { - let slice_to_return = self.read_to_slice_truncated(limit); + let slice_to_return = self.next_sub_slice_truncated(limit); let real_len = slice_to_return.len(); @@ -224,38 +223,47 @@ impl<'a, I: HasTargetBytes + HasLen> From<&'a I> for BytesReader<'a, I> { } } +/// Can be represented with a vector of bytes. +pub trait HasBytes: HasLen { + /// The bytes + fn bytes(&self) -> OwnedSlice; +} + // TODO change this to fn target_bytes(&self, buffer: &mut Vec) -> &[u8]; +/// Has a byte representation intended for the target. /// Can be represented with a vector of bytes. /// This representation is not necessarily deserializable. /// Instead, it can be used as bytes input for a target -pub trait HasTargetBytes: HasLen { - /// Target bytes, that can be written to a target - fn target_bytes(&self) -> OwnedSlice; +pub trait HasTargetBytes: HasBytes { + /// The target bytes. Defaults to the byte representation. + fn target_bytes(&self) -> OwnedSlice { + self.bytes() + } } -/// Contains mutateable and resizable bytes -pub trait HasMutatorBytes: HasLen { +/// Contains mutable and resizable bytes +pub trait HasMutatorBytes: HasBytes { /// The bytes - fn bytes(&self) -> &[u8]; + fn bytes_ref(&self) -> &[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`]. + /// See [`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>(&mut self, iter: I); - /// Splices the given target bytes according to [`alloc::vec::Vec::splice`]'s rules + /// Splices the given target bytes according to [`Vec::splice`]'s rules fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where R: RangeBounds, I: IntoIterator; - /// Drains the given target bytes according to [`alloc::vec::Vec::drain`]'s rules + /// Drains the given target bytes according to [`Vec::drain`]'s rules fn drain(&mut self, range: R) -> Drain<'_, u8> where R: RangeBounds; @@ -279,15 +287,6 @@ pub trait HasMutatorBytes: HasLen { } } -impl HasTargetBytes for I -where - I: HasMutatorBytes, -{ - fn target_bytes(&self) -> OwnedSlice { - OwnedSlice::from(self.bytes()) - } -} - /// A wrapper type that allows us to use mutators for Mutators for `&mut `[`Vec`]. #[derive(Debug)] pub struct MutVecInput<'a>(&'a mut Vec); @@ -304,8 +303,14 @@ impl<'a> HasLen for MutVecInput<'a> { } } +impl<'a> HasBytes for MutVecInput<'a> { + fn bytes(&self) -> OwnedSlice { + OwnedSlice::from(self.0.as_slice()) + } +} + impl<'a> HasMutatorBytes for MutVecInput<'a> { - fn bytes(&self) -> &[u8] { + fn bytes_ref(&self) -> &[u8] { self.0 } @@ -424,16 +429,16 @@ mod tests { let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); let mut bytes_reader = BytesReader::new(&bytes_input); - let bytes_read = bytes_reader.read_to_slice_truncated(2); + let bytes_read = bytes_reader.next_sub_slice_truncated(2); assert_eq!(*bytes_read.target_bytes(), [1, 2]); - let bytes_read = bytes_reader.read_to_slice_truncated(3); + let bytes_read = bytes_reader.next_sub_slice_truncated(3); assert_eq!(*bytes_read.target_bytes(), [3, 4, 5]); - let bytes_read = bytes_reader.read_to_slice_truncated(8); + let bytes_read = bytes_reader.next_sub_slice_truncated(8); assert_eq!(*bytes_read.target_bytes(), [6, 7]); - let bytes_read = bytes_reader.read_to_slice_truncated(8); + let bytes_read = bytes_reader.next_sub_slice_truncated(8); let bytes_read_ref: &[u8] = &[]; assert_eq!(&*bytes_read.target_bytes(), bytes_read_ref); } @@ -443,19 +448,19 @@ mod tests { let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); let mut bytes_reader = BytesReader::new(&bytes_input); - let bytes_read = bytes_reader.read_to_slice(2); + let bytes_read = bytes_reader.next_sub_input(2); assert_eq!(*bytes_read.unwrap().target_bytes(), [1, 2]); - let bytes_read = bytes_reader.read_to_slice(3); + let bytes_read = bytes_reader.next_sub_input(3); assert_eq!(*bytes_read.unwrap().target_bytes(), [3, 4, 5]); - let bytes_read = bytes_reader.read_to_slice(8); + let bytes_read = bytes_reader.next_sub_input(8); assert_eq!( *bytes_read.unwrap_err().partial().unwrap().target_bytes(), [6, 7] ); - let bytes_read = bytes_reader.read_to_slice(8); + let bytes_read = bytes_reader.next_sub_input(8); assert!(bytes_read.unwrap_err().empty()); } } diff --git a/libafl/src/mutators/multi.rs b/libafl/src/mutators/multi.rs index a4263951ba..0edd38e968 100644 --- a/libafl/src/mutators/multi.rs +++ b/libafl/src/mutators/multi.rs @@ -135,7 +135,7 @@ where let choice = name_choice % input.names().len(); let name = input.names()[choice].clone(); - let other_size = input.parts()[choice].bytes().len(); + let other_size = input.parts()[choice].bytes_ref().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -150,7 +150,7 @@ where .parts_by_name(&name) .filter(|&(p, _)| p != choice) .nth(part_choice % parts) - .map(|(id, part)| (id, part.bytes().len())); + .map(|(id, part)| (id, part.bytes_ref().len())); if let Some((part_idx, size)) = maybe_size { let target = state.rand_mut().below(size); @@ -180,7 +180,7 @@ where let choice = name_choice % other.names().len(); let name = &other.names()[choice]; - let other_size = other.parts()[choice].bytes().len(); + let other_size = other.parts()[choice].bytes_ref().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -193,7 +193,7 @@ where .nth(part_choice % parts) .unwrap(); drop(other_testcase); - let size = part.bytes().len(); + let size = part.bytes_ref().len(); let target = state.rand_mut().below(size); let range = rand_range(state, other_size, min(other_size, size - target)); @@ -239,7 +239,7 @@ where let choice = name_choice % input.names().len(); let name = input.names()[choice].clone(); - let other_size = input.parts()[choice].bytes().len(); + let other_size = input.parts()[choice].bytes_ref().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -254,7 +254,7 @@ where .parts_by_name(&name) .filter(|&(p, _)| p != choice) .nth(part_choice % parts) - .map(|(id, part)| (id, part.bytes().len())); + .map(|(id, part)| (id, part.bytes_ref().len())); if let Some((part_idx, size)) = maybe_size { let target = state.rand_mut().below(size); @@ -284,7 +284,7 @@ where let choice = name_choice % other.names().len(); let name = &other.names()[choice]; - let other_size = other.parts()[choice].bytes().len(); + let other_size = other.parts()[choice].bytes_ref().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -297,7 +297,7 @@ where .nth(part_choice % parts) .unwrap(); drop(other_testcase); - let size = part.bytes().len(); + let size = part.bytes_ref().len(); let target = state.rand_mut().below(size); let range = rand_range(state, other_size, min(other_size, size - target)); diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 6351ec05df..c29ead4e9c 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -126,7 +126,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { let bit = 1 << state.rand_mut().choose(0..8).unwrap(); @@ -162,7 +162,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { *state.rand_mut().choose(input.bytes_mut()).unwrap() ^= 0xff; @@ -196,7 +196,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -231,7 +231,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -266,7 +266,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -301,7 +301,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().is_empty() { + if input.bytes_ref().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -346,13 +346,13 @@ macro_rules! add_mutator_impl { input: &mut I, ) -> Result { - if input.bytes().len() < size_of::<$size>() { + if input.bytes_ref().len() < size_of::<$size>() { Ok(MutationResult::Skipped) } else { // choose a random window of bytes (windows overlap) and convert to $size let (index, bytes) = state .rand_mut() - .choose(input.bytes().windows(size_of::<$size>()).enumerate()).unwrap(); + .choose(input.bytes_ref().windows(size_of::<$size>()).enumerate()).unwrap(); let val = <$size>::from_ne_bytes(bytes.try_into().unwrap()); // mutate @@ -409,7 +409,7 @@ macro_rules! interesting_mutator_impl { { #[allow(clippy::cast_sign_loss)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes().len() < size_of::<$size>() { + if input.bytes_ref().len() < size_of::<$size>() { Ok(MutationResult::Skipped) } else { let bytes = input.bytes_mut(); @@ -457,7 +457,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size <= 2 { return Ok(MutationResult::Skipped); } @@ -496,7 +496,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 || size >= max_size { return Ok(MutationResult::Skipped); } @@ -543,7 +543,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 || size >= max_size { return Ok(MutationResult::Skipped); } @@ -559,7 +559,7 @@ where } } - let val = input.bytes()[state.rand_mut().below(size)]; + let val = input.bytes_ref()[state.rand_mut().below(size)]; input.resize(size + amount, 0); unsafe { @@ -597,7 +597,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size >= max_size { return Ok(MutationResult::Skipped); } @@ -650,13 +650,13 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(MutationResult::Skipped); } let range = rand_range(state, size, min(size, 16)); - let val = *state.rand_mut().choose(input.bytes()).unwrap(); + let val = *state.rand_mut().choose(input.bytes_ref()).unwrap(); let quantity = range.len(); buffer_set(input.bytes_mut(), range.start, quantity, val); @@ -689,7 +689,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -728,7 +728,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size <= 1 { return Ok(MutationResult::Skipped); } @@ -771,7 +771,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size <= 1 || size >= state.max_size() { return Ok(MutationResult::Skipped); } @@ -786,7 +786,7 @@ where unsafe { buffer_copy( &mut self.tmp_buf, - input.bytes(), + input.bytes_ref(), range.start, 0, range.len(), @@ -832,7 +832,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size <= 1 { return Ok(MutationResult::Skipped); } @@ -851,7 +851,7 @@ where // copy first range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes(), + input.bytes_ref(), first.start, 0, first.len(), @@ -887,7 +887,7 @@ where // copy first range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes(), + input.bytes_ref(), first.start, 0, first.len(), @@ -933,7 +933,7 @@ where // copy second range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes(), + input.bytes_ref(), second.start, 0, second.len(), @@ -968,7 +968,7 @@ where // copy second range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes(), + input.bytes_ref(), second.start, 0, second.len(), @@ -1050,7 +1050,7 @@ impl CrossoverInsertMutator { unsafe { buffer_copy( input.bytes_mut(), - other.bytes(), + other.bytes_ref(), range.start, target, range.len(), @@ -1067,7 +1067,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); let max_size = state.max_size(); if size >= max_size { return Ok(MutationResult::Skipped); @@ -1083,7 +1083,7 @@ where let other_size = { let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); - other_testcase.load_input(state.corpus())?.bytes().len() + other_testcase.load_input(state.corpus())?.bytes_ref().len() }; if other_size < 2 { @@ -1134,7 +1134,7 @@ impl CrossoverReplaceMutator { unsafe { buffer_copy( input.bytes_mut(), - other.bytes(), + other.bytes_ref(), range.start, target, range.len(), @@ -1151,7 +1151,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -1166,7 +1166,7 @@ where let other_size = { let mut testcase = state.corpus().get_from_all(id)?.borrow_mut(); - testcase.load_input(state.corpus())?.bytes().len() + testcase.load_input(state.corpus())?.bytes_ref().len() }; if other_size < 2 { @@ -1241,7 +1241,7 @@ where let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; - let (f, l) = locate_diffs(input.bytes(), other.bytes()); + let (f, l) = locate_diffs(input.bytes_ref(), other.bytes_ref()); if f != l && f >= 0 && l >= 2 { (f as usize, l as usize) @@ -1256,7 +1256,7 @@ where // Input will already be loaded. let other = other_testcase.input().as_ref().unwrap(); - input.splice(split_at.., other.bytes()[split_at..].iter().copied()); + input.splice(split_at.., other.bytes_ref()[split_at..].iter().copied()); Ok(MutationResult::Mutated) } diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index c625551277..a4af75419b 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -517,10 +517,10 @@ mod tests { let mut splice = SpliceMutator::new(); splice.mutate(&mut state, &mut input).unwrap(); - log::trace!("{:?}", input.bytes()); + log::trace!("{:?}", input.bytes_ref()); // The pre-seeded rand should have spliced at position 2. - assert_eq!(input.bytes(), &[b'a', b'b', b'f']); + assert_eq!(input.bytes_ref(), &[b'a', b'b', b'f']); } #[test] diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 186d1f59b1..093e128136 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -320,7 +320,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let size = input.bytes().len(); + let size = input.bytes_ref().len(); let off = state.rand_mut().below(size + 1); let meta = state.metadata_map().get::().unwrap(); @@ -371,7 +371,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -431,7 +431,7 @@ where { #[allow(clippy::too_many_lines)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -449,7 +449,7 @@ where let idx = state.rand_mut().below(cmps_len); let off = state.rand_mut().below(size); - let len = input.bytes().len(); + let len = input.bytes_ref().len(); let bytes = input.bytes_mut(); let meta = state.metadata_map().get::().unwrap(); @@ -561,7 +561,7 @@ where 'outer: for i in off..len { let mut size = core::cmp::min(v.0.len(), len - i); while size != 0 { - if v.0[0..size] == input.bytes()[i..i + size] { + if v.0[0..size] == input.bytes_ref()[i..i + size] { unsafe { buffer_copy(input.bytes_mut(), &v.1, 0, i, size); } @@ -572,7 +572,7 @@ where } size = core::cmp::min(v.1.len(), len - i); while size != 0 { - if v.1[0..size] == input.bytes()[i..i + size] { + if v.1[0..size] == input.bytes_ref()[i..i + size] { unsafe { buffer_copy(input.bytes_mut(), &v.0, 0, i, size); } @@ -1100,7 +1100,7 @@ where ) -> Result, Error> { // TODO // handle 128-bits logs - let size = input.bytes().len(); + let size = input.bytes_ref().len(); if size == 0 { return Ok(vec![]); } @@ -1125,9 +1125,9 @@ where let orig_cmpvals = cmp_meta.orig_cmpvals(); let new_cmpvals = cmp_meta.new_cmpvals(); let headers = cmp_meta.headers(); - let input_len = input.bytes().len(); + let input_len = input.bytes_ref().len(); let new_bytes = taint_meta.input_vec(); - let orig_bytes = input.bytes(); + let orig_bytes = input.bytes_ref(); let taint = taint_meta.ranges(); let mut ret = max_count.map_or_else(Vec::new, Vec::with_capacity); diff --git a/libafl/src/mutators/unicode/mod.rs b/libafl/src/mutators/unicode/mod.rs index 60a7b6cdb0..39c348cf01 100644 --- a/libafl/src/mutators/unicode/mod.rs +++ b/libafl/src/mutators/unicode/mod.rs @@ -224,7 +224,7 @@ fn rand_replace_range char>( ) -> MutationResult { let temp_range = rand_range(state, range.end - range.start, MAX_CHARS); let range = (range.start + temp_range.start)..(range.start + temp_range.end); - let range = match core::str::from_utf8(&input.0.bytes()[range.clone()]) { + let range = match core::str::from_utf8(&input.0.bytes_ref()[range.clone()]) { Ok(_) => range, Err(e) => range.start..(range.start + e.valid_up_to()), }; @@ -233,7 +233,7 @@ fn rand_replace_range char>( println!( "mutating range: {:?} ({:?})", range, - core::str::from_utf8(&input.0.bytes()[range.clone()]) + core::str::from_utf8(&input.0.bytes_ref()[range.clone()]) ); if range.start == range.end { return MutationResult::Skipped; @@ -261,7 +261,7 @@ fn rand_replace_range char>( } input.0.splice(range, replacement); - input.1 = extract_metadata(input.0.bytes()); + input.1 = extract_metadata(input.0.bytes_ref()); MutationResult::Mutated } @@ -283,11 +283,11 @@ where S: HasRand + HasMaxSize, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes().is_empty() { + if input.0.bytes_ref().is_empty() { return Ok(MutationResult::Skipped); } - let bytes = input.0.bytes(); + let bytes = input.0.bytes_ref(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -342,11 +342,11 @@ where S: HasRand + HasMaxSize, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes().is_empty() { + if input.0.bytes_ref().is_empty() { return Ok(MutationResult::Skipped); } - let bytes = input.0.bytes(); + let bytes = input.0.bytes_ref(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -389,7 +389,7 @@ where S: HasRand + HasMaxSize + HasMetadata, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes().is_empty() { + if input.0.bytes_ref().is_empty() { return Ok(MutationResult::Skipped); } @@ -404,7 +404,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let bytes = input.0.bytes(); + let bytes = input.0.bytes_ref(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -425,7 +425,7 @@ where } input.0.splice(range, token.iter().copied()); - input.1 = extract_metadata(input.0.bytes()); + input.1 = extract_metadata(input.0.bytes_ref()); return Ok(MutationResult::Mutated); } @@ -449,7 +449,7 @@ where S: HasRand + HasMaxSize + HasMetadata, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes().is_empty() { + if input.0.bytes_ref().is_empty() { return Ok(MutationResult::Skipped); } @@ -464,7 +464,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let bytes = input.0.bytes(); + let bytes = input.0.bytes_ref(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -485,7 +485,7 @@ where } input.0.splice(range, token.iter().copied()); - input.1 = extract_metadata(input.0.bytes()); + input.1 = extract_metadata(input.0.bytes_ref()); return Ok(MutationResult::Mutated); } @@ -523,10 +523,10 @@ mod test { )?; for _ in 0..(1 << 12) { - let metadata = extract_metadata(bytes.bytes()); + let metadata = extract_metadata(bytes.bytes_ref()); let mut input = (bytes, metadata); let _ = mutator.mutate(&mut state, &mut input); - println!("{:?}", core::str::from_utf8(input.0.bytes()).unwrap()); + println!("{:?}", core::str::from_utf8(input.0.bytes_ref()).unwrap()); bytes = input.0; } @@ -555,10 +555,10 @@ mod test { )?; for _ in 0..(1 << 12) { - let metadata = extract_metadata(bytes.bytes()); + let metadata = extract_metadata(bytes.bytes_ref()); let mut input = (bytes, metadata); let _ = mutator.mutate(&mut state, &mut input); - println!("{:?}", core::str::from_utf8(input.0.bytes()).unwrap()); + println!("{:?}", core::str::from_utf8(input.0.bytes_ref()).unwrap()); bytes = input.0; } diff --git a/libafl/src/stages/colorization.rs b/libafl/src/stages/colorization.rs index 2edab93288..c055e89068 100644 --- a/libafl/src/stages/colorization.rs +++ b/libafl/src/stages/colorization.rs @@ -228,7 +228,7 @@ where unsafe { buffer_copy( input.bytes_mut(), - changed.bytes(), + changed.bytes_ref(), range_start, range_start, copy_len, @@ -257,7 +257,7 @@ where unsafe { buffer_copy( input.bytes_mut(), - backup.bytes(), + backup.bytes_ref(), range_start, range_start, copy_len, @@ -300,11 +300,11 @@ where } if let Some(meta) = state.metadata_map_mut().get_mut::() { - meta.update(input.bytes().to_vec(), res); + meta.update(input.bytes_ref().to_vec(), res); // println!("meta: {:#?}", meta); } else { - let meta = TaintMetadata::new(input.bytes().to_vec(), res); + let meta = TaintMetadata::new(input.bytes_ref().to_vec(), res); state.add_metadata::(meta); } diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index d1d2741519..a56533f770 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -108,7 +108,7 @@ where let mut entry = state.corpus().get(corpus_id)?.borrow_mut(); let input = entry.input_mut().as_mut().unwrap(); - let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect(); + let payload: Vec<_> = input.bytes_ref().iter().map(|&x| Some(x)).collect(); let original = input.clone(); let meta = entry.metadata_map().get::().ok_or_else(|| { Error::key_not_found(format!( diff --git a/libafl/src/stages/unicode.rs b/libafl/src/stages/unicode.rs index 98957a015c..9a87e55a96 100644 --- a/libafl/src/stages/unicode.rs +++ b/libafl/src/stages/unicode.rs @@ -119,7 +119,7 @@ where let input = tc.load_input(state.corpus())?; - let bytes = input.bytes(); + let bytes = input.bytes_ref(); let metadata = extract_metadata(bytes); tc.add_metadata(metadata); diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 1a9efaba89..012424eaa6 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -12,7 +12,6 @@ // For `std::simd` #![cfg_attr(nightly, feature(portable_simd))] // For `core::error` -#![cfg_attr(nightly, feature(error_in_core))] #![warn(clippy::cargo)] #![allow(ambiguous_glob_reexports)] #![deny(clippy::cargo_common_metadata)] diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs index dab8f27433..d1919232ca 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs @@ -110,7 +110,7 @@ fn minimize_crash_with_mutator>( } let mut testcase = state.testcase_mut(id)?; - let input = testcase.load_input(state.corpus())?.bytes().to_vec(); + let input = testcase.load_input(state.corpus())?.bytes_ref().to_vec(); drop(testcase); if input.len() >= size { eprintln!( diff --git a/libafl_qemu/src/helpers/injections.rs b/libafl_qemu/src/helpers/injections.rs index d5a0ca1130..8c429694a7 100644 --- a/libafl_qemu/src/helpers/injections.rs +++ b/libafl_qemu/src/helpers/injections.rs @@ -303,9 +303,8 @@ where } else { libs.iter() .filter_map(|lib| find_function(qemu, &lib.name, name, lib.off).unwrap()) - .map(|func_pc| { + .inspect(|&func_pc| { log::info!("Injections: Function {name} found at {func_pc:#x}",); - func_pc }) .collect() }; diff --git a/libafl_targets/src/libfuzzer/mutators.rs b/libafl_targets/src/libfuzzer/mutators.rs index 0e8fee9848..c0d93c290d 100644 --- a/libafl_targets/src/libfuzzer/mutators.rs +++ b/libafl_targets/src/libfuzzer/mutators.rs @@ -173,7 +173,7 @@ where drop(result); if succeeded { - let target = intermediary.bytes(); + let target = intermediary.bytes_ref(); if target.as_slice().len() > max_size { self.result .replace(Err(Error::illegal_state("Mutation result was too long!"))) @@ -322,7 +322,7 @@ where input: &mut S::Input, ) -> Result { let seed = state.rand_mut().next(); - let target = input.bytes(); + let target = input.bytes_ref(); let mut bytes = Vec::with_capacity(state.max_size()); bytes.extend_from_slice(target.as_slice()); bytes.resize(state.max_size(), 0); @@ -406,12 +406,12 @@ where let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; - let data2 = Vec::from(other.bytes()); + let data2 = Vec::from(other.bytes_ref()); drop(other_testcase); let seed = state.rand_mut().next(); let mut out = vec![0u8; state.max_size()]; - let data1 = input.bytes(); + let data1 = input.bytes_ref(); // we assume that the fuzzer did not use this mutator, but instead utilised their own let result = Rc::new(RefCell::new(Ok(MutationResult::Mutated))); diff --git a/utils/libafl_benches/benches/hash_speeds.rs b/utils/libafl_benches/benches/hash_speeds.rs index e1aee1cab2..04c113a668 100644 --- a/utils/libafl_benches/benches/hash_speeds.rs +++ b/utils/libafl_benches/benches/hash_speeds.rs @@ -22,17 +22,16 @@ fn criterion_benchmark(c: &mut Criterion) { });*/ c.bench_function("ahash", |b| { b.iter(|| { - let mut hasher = - black_box(ahash::RandomState::with_seeds(123, 456, 789, 123).build_hasher()); + let mut hasher = ahash::RandomState::with_seeds(123, 456, 789, 123).build_hasher(); hasher.write(black_box(&bench_vec)); - hasher.finish(); + black_box(hasher.finish()) }); }); c.bench_function("fxhash", |b| { b.iter(|| { - let mut hasher = black_box(rustc_hash::FxHasher::default()); + let mut hasher = rustc_hash::FxHasher::default(); hasher.write(black_box(&bench_vec)); - hasher.finish(); + black_box(hasher.finish()) }); }); } From 6c28a92b480592915d8b6fabc93ffb30274b0b04 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Thu, 4 Jul 2024 11:07:57 +0200 Subject: [PATCH 12/27] change interface --- libafl/src/inputs/bytessub.rs | 32 ++++++++++++++++++++------------ libafl/src/inputs/mod.rs | 35 ++++++++++++++++------------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index f95a6f04e3..c3c1c3e890 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -41,25 +41,24 @@ where /// /// A mutable version is available: [`BytesSubInputMut`]. #[derive(Debug)] -pub struct BytesSubInput<'a> { +pub struct BytesSlice<'a> { /// The (complete) parent input we will work on parent_input: OwnedSlice<'a, u8>, /// The range inside the parent input we will work on range: Range, } -impl<'a> BytesSubInput<'a> { +impl<'a> BytesSlice<'a> { /// Creates a new [`BytesSubInputMut`] 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(parent_input: &'a I, range: R) -> Self + pub fn new(parent_slice: OwnedSlice<'a, u8>, range: R) -> Self where - I: HasBytes, R: RangeBounds, { - let parent_len = parent_input.len(); + let parent_len = parent_slice.len(); - let ret = BytesSubInput { - parent_input: parent_input.bytes(), + let ret = BytesSlice { + parent_input: parent_slice, range: Range { start: start_index(&range), end: end_index(&range, parent_len), @@ -69,6 +68,15 @@ impl<'a> BytesSubInput<'a> { ret } + /// Creates a new [`BytesSubInputMut`] 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 with_slice(parent_slice: &'a [u8], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + /// The parent input #[must_use] pub fn parent_input(&self) -> OwnedSlice<'a, u8> { @@ -88,9 +96,9 @@ impl<'a> BytesSubInput<'a> { } /// Creates a sub range in the current own range - pub fn sub_range(&self, range: R2) -> (Bound, Bound) + pub fn sub_range(&self, range: R) -> (Bound, Bound) where - R2: RangeBounds, + R: RangeBounds, { let start = match (self.range.start_bound(), range.start_bound()) { (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, @@ -388,20 +396,20 @@ where } } -impl<'a> HasLen for BytesSubInput<'a> { +impl<'a> HasLen for BytesSlice<'a> { #[inline] fn len(&self) -> usize { self.range.len() } } -impl<'a> HasBytes for BytesSubInput<'a> { +impl<'a> HasBytes for BytesSlice<'a> { fn bytes(&self) -> OwnedSlice { self.parent_input.slice(self.range.clone()) } } -impl<'a> HasTargetBytes for BytesSubInput<'a> {} +impl<'a> HasTargetBytes for BytesSlice<'a> {} #[cfg(test)] mod tests { diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 92d6a247e0..84594d247e 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::{BytesSubInput, BytesSubInputMut}; +pub use bytessub::{BytesSlice, BytesSubInputMut}; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -132,10 +132,10 @@ impl HasLen for NopInput { } /// Target bytes wrapper keeping track of the current read position. -/// Convenient wrapper when bytes must be split it in multiple subinputs. +/// Convenient wrapper when bytes must be split in multiple subinputs. #[derive(Debug)] -pub struct BytesReader<'a, I> { - parent_input: &'a I, +pub struct BytesReader<'a> { + parent_input: &'a [u8], pos: usize, } @@ -147,7 +147,7 @@ pub enum PartialBytesSubInput<'a> { /// The slice is empty, and thus not kept Empty, /// The slice is strictly smaller than the expected one. - Partial(BytesSubInput<'a>), + Partial(BytesSlice<'a>), } impl<'a> PartialBytesSubInput<'a> { @@ -159,7 +159,7 @@ impl<'a> PartialBytesSubInput<'a> { /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. #[must_use] - pub fn partial(self) -> Option> { + pub fn partial(self) -> Option> { #[allow(clippy::match_wildcard_for_single_variants)] match self { PartialBytesSubInput::Partial(partial_slice) => Some(partial_slice), @@ -168,13 +168,10 @@ impl<'a> PartialBytesSubInput<'a> { } } -impl<'a, I> BytesReader<'a, I> -where - I: HasTargetBytes + HasLen, -{ +impl<'a> BytesReader<'a> { /// Create a new [`BytesReader`]. /// The position of the reader is initialized to 0. - pub fn new(input: &'a I) -> Self { + pub fn new(input: &'a [u8]) -> Self { Self { parent_input: input, pos: 0, @@ -185,8 +182,8 @@ where /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. /// This function does not provide any feedback on whether the slice was cropped or not. #[must_use] - pub fn next_sub_slice_truncated(&mut self, limit: usize) -> BytesSubInput<'a> { - let sub_input = BytesSubInput::new(self.parent_input, self.pos..(self.pos + limit)); + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> BytesSlice<'a> { + let sub_input = BytesSlice::with_slice(self.parent_input, self.pos..(self.pos + limit)); self.pos += sub_input.len(); @@ -202,7 +199,7 @@ where pub fn next_sub_input( &mut self, limit: usize, - ) -> Result, PartialBytesSubInput<'a>> { + ) -> Result, PartialBytesSubInput<'a>> { let slice_to_return = self.next_sub_slice_truncated(limit); let real_len = slice_to_return.len(); @@ -217,8 +214,8 @@ where } } -impl<'a, I: HasTargetBytes + HasLen> From<&'a I> for BytesReader<'a, I> { - fn from(input: &'a I) -> Self { +impl<'a> From<&'a [u8]> for BytesReader<'a> { + fn from(input: &'a [u8]) -> Self { Self::new(input) } } @@ -268,13 +265,13 @@ pub trait HasMutatorBytes: HasBytes { where R: RangeBounds; - /// Creates a [`BytesSubInput`] from this input, that can be used for local mutations. - fn sub_input(&self, range: R) -> BytesSubInput + /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. + fn sub_input(&self, range: R) -> BytesSlice where R: RangeBounds, Self: Sized, { - BytesSubInput::new(self, range) + BytesSlice::new(self.bytes(), range) } /// Creates a [`BytesSubInputMut`] from this input, that can be used for local mutations. From e3e2d8e049ad1d52a0f6f42baf720f299f099f18 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Thu, 4 Jul 2024 11:30:08 +0200 Subject: [PATCH 13/27] fix tests --- libafl/src/inputs/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 84594d247e..542a52e8ad 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -419,11 +419,11 @@ where #[cfg(test)] mod tests { - use crate::inputs::{BytesInput, BytesReader, HasTargetBytes}; + use crate::inputs::{BytesReader, HasTargetBytes}; #[test] fn test_bytesreader_toslice_unchecked() { - let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; let mut bytes_reader = BytesReader::new(&bytes_input); let bytes_read = bytes_reader.next_sub_slice_truncated(2); @@ -442,7 +442,7 @@ mod tests { #[test] fn test_bytesreader_toslice() { - let bytes_input = BytesInput::new(vec![1, 2, 3, 4, 5, 6, 7]); + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; let mut bytes_reader = BytesReader::new(&bytes_input); let bytes_read = bytes_reader.next_sub_input(2); From 31aa9555b898876439beae900dd4b5414d4275c4 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Thu, 4 Jul 2024 11:31:09 +0200 Subject: [PATCH 14/27] clippers --- libafl/src/inputs/bytessub.rs | 6 ++---- libafl/src/inputs/mod.rs | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index c3c1c3e890..abb7f47c49 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -57,15 +57,13 @@ impl<'a> BytesSlice<'a> { { let parent_len = parent_slice.len(); - let ret = BytesSlice { + BytesSlice { parent_input: parent_slice, range: Range { start: start_index(&range), end: end_index(&range, parent_len), }, - }; - - ret + } } /// Creates a new [`BytesSubInputMut`] that's a view on an input with mutator bytes. diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 542a52e8ad..0fd5cb8302 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -171,6 +171,7 @@ impl<'a> PartialBytesSubInput<'a> { impl<'a> BytesReader<'a> { /// Create a new [`BytesReader`]. /// The position of the reader is initialized to 0. + #[must_use] pub fn new(input: &'a [u8]) -> Self { Self { parent_input: input, From 8c76adb7b6a3ae5d67fde42f0a35daba9cfbf84a Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 15 Jul 2024 11:04:34 +0200 Subject: [PATCH 15/27] use byte slice for subbytes --- libafl/src/inputs/bytessub.rs | 170 ++++++++++++++++++-- libafl/src/inputs/mod.rs | 166 ++++++++++++++++++- utils/libafl_benches/benches/hash_speeds.rs | 4 +- 3 files changed, 317 insertions(+), 23 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 262e7ff7dc..ef681ef201 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -1,4 +1,4 @@ -//! [`BytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice +//! [`BytesSubInputMut`] is a wrapper input that can be used to mutate parts of a byte slice use alloc::vec::Vec; use core::{ @@ -6,7 +6,7 @@ use core::{ ops::{Bound, Range, RangeBounds}, }; -use libafl_bolts::HasLen; +use libafl_bolts::{ownedref::OwnedSlice, HasLen}; use super::HasMutatorBytes; @@ -27,14 +27,124 @@ fn end_index(range: &R, max_len: usize) -> usize where R: RangeBounds, { - match range.end_bound() { + let end = match range.end_bound() { Bound::Unbounded => max_len, Bound::Included(end) => end + 1, Bound::Excluded(end) => *end, + }; + + min(end, max_len) +} + +/// An immutable contiguous subslice of an input implementing [`HasTargetBytes`]. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// A mutable version is available: [`BytesSubInputMut`]. +#[derive(Debug)] +pub struct BytesSlice<'a> { + /// The (complete) parent input we will work on + parent_slice: OwnedSlice<'a, u8>, + /// The range inside the parent input we will work on + range: Range, +} + +impl<'a> BytesSlice<'a> { + /// Creates a new [`BytesSubInputMut`] 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(parent_slice: OwnedSlice<'a, u8>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + BytesSlice { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn bytes(&self) -> &[u8] { + &self.parent_slice[self.range.clone()] + } + + /// Creates a new [`BytesSubInputMut`] 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 with_slice(parent_slice: &'a [u8], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(&self) -> OwnedSlice<'a, u8> { + self.parent_slice.clone() + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + 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) } } -/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on +/// The [`BytesSubInputMut`] 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 @@ -85,9 +195,9 @@ where /// assert_eq!(bytes_input.bytes(), [1, 2, 3, 4, 42, 42, 42, 5]); /// ``` /// -/// The input supports all methods in the [`HasMutatorBytes`] trait. +/// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. #[derive(Debug)] -pub struct BytesSubInput<'a, I> +pub struct BytesSubInputMut<'a, I> where I: HasMutatorBytes + ?Sized, { @@ -97,11 +207,11 @@ where pub(crate) range: Range, } -impl<'a, I> BytesSubInput<'a, I> +impl<'a, I> BytesSubInputMut<'a, I> where I: HasMutatorBytes + ?Sized + HasLen, { - /// Creates a new [`BytesSubInput`] that's a view on an input with mutator bytes. + /// Creates a new [`BytesSubInputMut`] 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(parent_input: &'a mut I, range: R) -> Self where @@ -109,7 +219,7 @@ where { let parent_len = parent_input.len(); - BytesSubInput { + BytesSubInputMut { parent_input, range: Range { start: start_index(&range), @@ -173,7 +283,7 @@ where } } -impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I> +impl<'a, I> HasMutatorBytes for BytesSubInputMut<'a, I> where I: HasMutatorBytes + HasLen, { @@ -272,13 +382,20 @@ where } } -impl<'a, I> HasLen for BytesSubInput<'a, I> +impl<'a> HasLen for BytesSlice<'a> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, I> HasLen for BytesSubInputMut<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasMutatorBytes { #[inline] fn len(&self) -> usize { - self.range.end - self.range.start + self.range.len() } } @@ -303,6 +420,20 @@ mod tests { #[test] fn test_bytessubinput() { + let (bytes_input, _) = init_bytes_input(); + + let sub_input = bytes_input.sub_bytes(0..1); + assert_eq!(*sub_input.bytes(), [1]); + + let sub_input = bytes_input.sub_bytes(1..=2); + assert_eq!(*sub_input.bytes(), [2, 3]); + + let sub_input = bytes_input.sub_bytes(..); + assert_eq!(*sub_input.bytes(), [1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_mutablebytessubinput() { let (mut bytes_input, len_orig) = init_bytes_input(); let mut sub_input = bytes_input.sub_input(0..1); @@ -413,6 +544,19 @@ mod tests { #[test] fn test_ranges() { + let bytes_input = BytesInput::new(vec![1, 2, 3]); + + assert_eq!(bytes_input.sub_bytes(..1).start_index(), 0); + assert_eq!(bytes_input.sub_bytes(1..=1).start_index(), 1); + assert_eq!(bytes_input.sub_bytes(..1).end_index(), 1); + assert_eq!(bytes_input.sub_bytes(..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes(1..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes(1..).end_index(), 3); + assert_eq!(bytes_input.sub_bytes(..3).end_index(), 3); + } + + #[test] + fn test_ranges_mut() { let mut bytes_input = BytesInput::new(vec![1, 2, 3]); assert_eq!(bytes_input.sub_input(..1).start_index(), 0); diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index a915d3faf0..6d31e29557 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::BytesSubInput; +pub use bytessub::{BytesSlice, BytesSubInputMut}; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -123,7 +123,104 @@ impl HasTargetBytes for NopInput { } } +impl HasLen for NopInput { + fn len(&self) -> usize { + 0 + } +} + +/// Target bytes wrapper keeping track of the current read position. +/// Convenient wrapper when bytes must be split in multiple subinputs. +#[derive(Debug)] +pub struct BytesReader<'a> { + parent_input: &'a [u8], + pos: usize, +} + +/// Representation of a partial slice +/// This is used when providing a slice smaller than the expected one. +/// It notably happens when trying to read the end of an input. +#[derive(Debug)] +pub enum PartialBytesSubInput<'a> { + /// The slice is empty, and thus not kept + Empty, + /// The slice is strictly smaller than the expected one. + Partial(BytesSlice<'a>), +} + +impl<'a> PartialBytesSubInput<'a> { + /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. + #[must_use] + pub fn empty(self) -> bool { + matches!(self, PartialBytesSubInput::Empty) + } + + /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. + #[must_use] + pub fn partial(self) -> Option> { + #[allow(clippy::match_wildcard_for_single_variants)] + match self { + PartialBytesSubInput::Partial(partial_slice) => Some(partial_slice), + _ => None, + } + } +} + +impl<'a> BytesReader<'a> { + /// Create a new [`BytesReader`]. + /// The position of the reader is initialized to 0. + #[must_use] + pub fn new(input: &'a [u8]) -> Self { + Self { + parent_input: input, + pos: 0, + } + } + + /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. + /// This function does not provide any feedback on whether the slice was cropped or not. + #[must_use] + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> BytesSlice<'a> { + let sub_input = BytesSlice::with_slice(self.parent_input, self.pos..(self.pos + limit)); + + self.pos += sub_input.len(); + + sub_input + } + + /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. + /// The function returns + /// - `Ok(Slice)` if the returned slice has `limit` bytes. + /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` bytes and is not empty. + /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. + pub fn next_sub_input( + &mut self, + limit: usize, + ) -> Result, PartialBytesSubInput<'a>> { + let slice_to_return = self.next_sub_slice_truncated(limit); + + let real_len = slice_to_return.len(); + + if real_len == 0 { + Err(PartialBytesSubInput::Empty) + } else if real_len < limit { + Err(PartialBytesSubInput::Partial(slice_to_return)) + } else { + Ok(slice_to_return) + } + } +} + +impl<'a> From<&'a [u8]> for BytesReader<'a> { + fn from(input: &'a [u8]) -> Self { + Self::new(input) + } +} + // TODO change this to fn target_bytes(&self, buffer: &mut Vec) -> &[u8]; +/// Has a byte representation intended for the target. /// Can be represented with a vector of bytes. /// This representation is not necessarily deserializable. /// Instead, it can be used as bytes input for a target @@ -132,7 +229,7 @@ pub trait HasTargetBytes { fn target_bytes(&self) -> OwnedSlice; } -/// Contains mutateable and resizable bytes +/// Contains mutable and resizable bytes pub trait HasMutatorBytes: HasLen { /// The bytes fn bytes(&self) -> &[u8]; @@ -142,29 +239,37 @@ pub trait HasMutatorBytes: HasLen { /// 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`]. + /// See [`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>(&mut self, iter: I); - /// Splices the given target bytes according to [`alloc::vec::Vec::splice`]'s rules + /// Splices the given target bytes according to [`Vec::splice`]'s rules fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where R: RangeBounds, I: IntoIterator; - /// Drains the given target bytes according to [`alloc::vec::Vec::drain`]'s rules + /// Drains the given target bytes according to [`Vec::drain`]'s rules fn drain(&mut self, range: R) -> Drain<'_, u8> where R: RangeBounds; - /// Creates a [`BytesSubInput`] from this input, that can be used for local mutations. - fn sub_input(&mut self, range: R) -> BytesSubInput + /// Creates a [`BytesSlice`] from this input, that can be used to slice a byte array. + fn sub_bytes(&self, range: R) -> BytesSlice where R: RangeBounds, { - BytesSubInput::new(self, range) + BytesSlice::new(OwnedSlice::from(self.bytes()), range) + } + + /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. + fn sub_input(&mut self, range: R) -> BytesSubInputMut + where + R: RangeBounds, + { + BytesSubInputMut::new(self, range) } } @@ -294,3 +399,48 @@ where (self.convert_cb)(input) } } + +#[cfg(test)] +mod tests { + use crate::inputs::BytesReader; + + #[test] + fn test_bytesreader_toslice_unchecked() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = BytesReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_slice_truncated(2); + assert_eq!(*bytes_read.bytes(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(3); + assert_eq!(*bytes_read.bytes(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + assert_eq!(*bytes_read.bytes(), [6, 7]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + let bytes_read_ref: &[u8] = &[]; + assert_eq!(&*bytes_read.bytes(), bytes_read_ref); + } + + #[test] + fn test_bytesreader_toslice() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = BytesReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_input(2); + assert_eq!(*bytes_read.unwrap().bytes(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_input(3); + assert_eq!(*bytes_read.unwrap().bytes(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_input(8); + assert_eq!( + *bytes_read.unwrap_err().partial().unwrap().bytes(), + [6, 7] + ); + + let bytes_read = bytes_reader.next_sub_input(8); + assert!(bytes_read.unwrap_err().empty()); + } +} diff --git a/utils/libafl_benches/benches/hash_speeds.rs b/utils/libafl_benches/benches/hash_speeds.rs index 1ae50dbd8d..fa30d1d576 100644 --- a/utils/libafl_benches/benches/hash_speeds.rs +++ b/utils/libafl_benches/benches/hash_speeds.rs @@ -15,7 +15,7 @@ fn criterion_benchmark(c: &mut Criterion) { } c.bench_function("xxh3", |b| { - b.iter(|| xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0)); + b.iter(|| black_box(xxh3::xxh3_64_with_seed(&bench_vec, 0))); }); /*c.bench_function("const_xxh3", |b| { b.iter(|| const_xxh3::xxh3_64_with_seed(black_box(&bench_vec), 0)) @@ -30,7 +30,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); c.bench_function("fxhash", |b| { b.iter(|| { - let mut hasher = black_box(rustc_hash::FxHasher::default()); + let mut hasher = rustc_hash::FxHasher::default(); hasher.write(black_box(&bench_vec)); black_box(hasher.finish()); }); From 69e34d52ba9920325e7ab9d23633fa6097ed0063 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 15 Jul 2024 11:17:31 +0200 Subject: [PATCH 16/27] adapt to main --- libafl/src/inputs/bytes.rs | 36 +++++----- libafl/src/mutators/multi.rs | 16 ++--- libafl/src/mutators/mutations.rs | 66 +++++++++---------- libafl/src/mutators/token_mutations.rs | 18 ++--- libafl/src/mutators/unicode/mod.rs | 34 +++++----- libafl/src/stages/colorization.rs | 8 +-- libafl/src/stages/generalization.rs | 2 +- libafl/src/stages/unicode.rs | 2 +- .../libafl_libfuzzer_runtime/src/tmin.rs | 2 +- libafl_targets/src/libfuzzer/mutators.rs | 8 +-- 10 files changed, 95 insertions(+), 97 deletions(-) diff --git a/libafl/src/inputs/bytes.rs b/libafl/src/inputs/bytes.rs index 21c49a0c67..127e672953 100644 --- a/libafl/src/inputs/bytes.rs +++ b/libafl/src/inputs/bytes.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; use crate::{ corpus::CorpusId, - inputs::{HasBytes, HasMutatorBytes, HasTargetBytes, Input}, + inputs::{HasMutatorBytes, HasTargetBytes, Input}, }; /// A bytes input is the basic input @@ -52,7 +52,7 @@ impl Input for BytesInput { /// Generate a name for this input fn generate_name(&self, _id: Option) -> String { let mut hasher = RandomState::with_seeds(0, 0, 0, 0).build_hasher(); - hasher.write(self.bytes_ref()); + hasher.write(self.bytes()); format!("{:016x}", hasher.finish()) } } @@ -64,25 +64,9 @@ impl From for Rc> { } } -impl HasLen for BytesInput { - #[inline] - fn len(&self) -> usize { - self.bytes.len() - } -} - -impl HasBytes for BytesInput { - #[inline] - fn bytes(&self) -> OwnedSlice { - OwnedSlice::from(&self.bytes) - } -} - -impl HasTargetBytes for BytesInput {} - impl HasMutatorBytes for BytesInput { #[inline] - fn bytes_ref(&self) -> &[u8] { + fn bytes(&self) -> &[u8] { &self.bytes } @@ -115,6 +99,20 @@ impl HasMutatorBytes for BytesInput { } } +impl HasTargetBytes for BytesInput { + #[inline] + fn target_bytes(&self) -> OwnedSlice { + OwnedSlice::from(&self.bytes) + } +} + +impl HasLen for BytesInput { + #[inline] + fn len(&self) -> usize { + self.bytes.len() + } +} + impl From> for BytesInput { fn from(bytes: Vec) -> Self { Self::new(bytes) diff --git a/libafl/src/mutators/multi.rs b/libafl/src/mutators/multi.rs index 0edd38e968..a4263951ba 100644 --- a/libafl/src/mutators/multi.rs +++ b/libafl/src/mutators/multi.rs @@ -135,7 +135,7 @@ where let choice = name_choice % input.names().len(); let name = input.names()[choice].clone(); - let other_size = input.parts()[choice].bytes_ref().len(); + let other_size = input.parts()[choice].bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -150,7 +150,7 @@ where .parts_by_name(&name) .filter(|&(p, _)| p != choice) .nth(part_choice % parts) - .map(|(id, part)| (id, part.bytes_ref().len())); + .map(|(id, part)| (id, part.bytes().len())); if let Some((part_idx, size)) = maybe_size { let target = state.rand_mut().below(size); @@ -180,7 +180,7 @@ where let choice = name_choice % other.names().len(); let name = &other.names()[choice]; - let other_size = other.parts()[choice].bytes_ref().len(); + let other_size = other.parts()[choice].bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -193,7 +193,7 @@ where .nth(part_choice % parts) .unwrap(); drop(other_testcase); - let size = part.bytes_ref().len(); + let size = part.bytes().len(); let target = state.rand_mut().below(size); let range = rand_range(state, other_size, min(other_size, size - target)); @@ -239,7 +239,7 @@ where let choice = name_choice % input.names().len(); let name = input.names()[choice].clone(); - let other_size = input.parts()[choice].bytes_ref().len(); + let other_size = input.parts()[choice].bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -254,7 +254,7 @@ where .parts_by_name(&name) .filter(|&(p, _)| p != choice) .nth(part_choice % parts) - .map(|(id, part)| (id, part.bytes_ref().len())); + .map(|(id, part)| (id, part.bytes().len())); if let Some((part_idx, size)) = maybe_size { let target = state.rand_mut().below(size); @@ -284,7 +284,7 @@ where let choice = name_choice % other.names().len(); let name = &other.names()[choice]; - let other_size = other.parts()[choice].bytes_ref().len(); + let other_size = other.parts()[choice].bytes().len(); if other_size < 2 { return Ok(MutationResult::Skipped); } @@ -297,7 +297,7 @@ where .nth(part_choice % parts) .unwrap(); drop(other_testcase); - let size = part.bytes_ref().len(); + let size = part.bytes().len(); let target = state.rand_mut().below(size); let range = rand_range(state, other_size, min(other_size, size - target)); diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index c29ead4e9c..6351ec05df 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -126,7 +126,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { let bit = 1 << state.rand_mut().choose(0..8).unwrap(); @@ -162,7 +162,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { *state.rand_mut().choose(input.bytes_mut()).unwrap() ^= 0xff; @@ -196,7 +196,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -231,7 +231,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -266,7 +266,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -301,7 +301,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().is_empty() { + if input.bytes().is_empty() { Ok(MutationResult::Skipped) } else { let byte = state.rand_mut().choose(input.bytes_mut()).unwrap(); @@ -346,13 +346,13 @@ macro_rules! add_mutator_impl { input: &mut I, ) -> Result { - if input.bytes_ref().len() < size_of::<$size>() { + if input.bytes().len() < size_of::<$size>() { Ok(MutationResult::Skipped) } else { // choose a random window of bytes (windows overlap) and convert to $size let (index, bytes) = state .rand_mut() - .choose(input.bytes_ref().windows(size_of::<$size>()).enumerate()).unwrap(); + .choose(input.bytes().windows(size_of::<$size>()).enumerate()).unwrap(); let val = <$size>::from_ne_bytes(bytes.try_into().unwrap()); // mutate @@ -409,7 +409,7 @@ macro_rules! interesting_mutator_impl { { #[allow(clippy::cast_sign_loss)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - if input.bytes_ref().len() < size_of::<$size>() { + if input.bytes().len() < size_of::<$size>() { Ok(MutationResult::Skipped) } else { let bytes = input.bytes_mut(); @@ -457,7 +457,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size <= 2 { return Ok(MutationResult::Skipped); } @@ -496,7 +496,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 || size >= max_size { return Ok(MutationResult::Skipped); } @@ -543,7 +543,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 || size >= max_size { return Ok(MutationResult::Skipped); } @@ -559,7 +559,7 @@ where } } - let val = input.bytes_ref()[state.rand_mut().below(size)]; + let val = input.bytes()[state.rand_mut().below(size)]; input.resize(size + amount, 0); unsafe { @@ -597,7 +597,7 @@ where { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { let max_size = state.max_size(); - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size >= max_size { return Ok(MutationResult::Skipped); } @@ -650,13 +650,13 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } let range = rand_range(state, size, min(size, 16)); - let val = *state.rand_mut().choose(input.bytes_ref()).unwrap(); + let val = *state.rand_mut().choose(input.bytes()).unwrap(); let quantity = range.len(); buffer_set(input.bytes_mut(), range.start, quantity, val); @@ -689,7 +689,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -728,7 +728,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size <= 1 { return Ok(MutationResult::Skipped); } @@ -771,7 +771,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size <= 1 || size >= state.max_size() { return Ok(MutationResult::Skipped); } @@ -786,7 +786,7 @@ where unsafe { buffer_copy( &mut self.tmp_buf, - input.bytes_ref(), + input.bytes(), range.start, 0, range.len(), @@ -832,7 +832,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size <= 1 { return Ok(MutationResult::Skipped); } @@ -851,7 +851,7 @@ where // copy first range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes_ref(), + input.bytes(), first.start, 0, first.len(), @@ -887,7 +887,7 @@ where // copy first range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes_ref(), + input.bytes(), first.start, 0, first.len(), @@ -933,7 +933,7 @@ where // copy second range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes_ref(), + input.bytes(), second.start, 0, second.len(), @@ -968,7 +968,7 @@ where // copy second range to tmp buffer_copy( &mut self.tmp_buf, - input.bytes_ref(), + input.bytes(), second.start, 0, second.len(), @@ -1050,7 +1050,7 @@ impl CrossoverInsertMutator { unsafe { buffer_copy( input.bytes_mut(), - other.bytes_ref(), + other.bytes(), range.start, target, range.len(), @@ -1067,7 +1067,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); let max_size = state.max_size(); if size >= max_size { return Ok(MutationResult::Skipped); @@ -1083,7 +1083,7 @@ where let other_size = { let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); - other_testcase.load_input(state.corpus())?.bytes_ref().len() + other_testcase.load_input(state.corpus())?.bytes().len() }; if other_size < 2 { @@ -1134,7 +1134,7 @@ impl CrossoverReplaceMutator { unsafe { buffer_copy( input.bytes_mut(), - other.bytes_ref(), + other.bytes(), range.start, target, range.len(), @@ -1151,7 +1151,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -1166,7 +1166,7 @@ where let other_size = { let mut testcase = state.corpus().get_from_all(id)?.borrow_mut(); - testcase.load_input(state.corpus())?.bytes_ref().len() + testcase.load_input(state.corpus())?.bytes().len() }; if other_size < 2 { @@ -1241,7 +1241,7 @@ where let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; - let (f, l) = locate_diffs(input.bytes_ref(), other.bytes_ref()); + let (f, l) = locate_diffs(input.bytes(), other.bytes()); if f != l && f >= 0 && l >= 2 { (f as usize, l as usize) @@ -1256,7 +1256,7 @@ where // Input will already be loaded. let other = other_testcase.input().as_ref().unwrap(); - input.splice(split_at.., other.bytes_ref()[split_at..].iter().copied()); + input.splice(split_at.., other.bytes()[split_at..].iter().copied()); Ok(MutationResult::Mutated) } diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index bcf5f7b93d..95480dd09e 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -320,7 +320,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let size = input.bytes_ref().len(); + let size = input.bytes().len(); let off = state.rand_mut().below(size + 1); let meta = state.metadata_map().get::().unwrap(); @@ -371,7 +371,7 @@ where I: HasMutatorBytes, { fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -431,7 +431,7 @@ where { #[allow(clippy::too_many_lines)] fn mutate(&mut self, state: &mut S, input: &mut I) -> Result { - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(MutationResult::Skipped); } @@ -449,7 +449,7 @@ where let idx = state.rand_mut().below(cmps_len); let off = state.rand_mut().below(size); - let len = input.bytes_ref().len(); + let len = input.bytes().len(); let bytes = input.bytes_mut(); let meta = state.metadata_map().get::().unwrap(); @@ -561,7 +561,7 @@ where 'outer: for i in off..len { let mut size = core::cmp::min(v.0.len(), len - i); while size != 0 { - if v.0[0..size] == input.bytes_ref()[i..i + size] { + if v.0[0..size] == input.bytes()[i..i + size] { unsafe { buffer_copy(input.bytes_mut(), &v.1, 0, i, size); } @@ -572,7 +572,7 @@ where } size = core::cmp::min(v.1.len(), len - i); while size != 0 { - if v.1[0..size] == input.bytes_ref()[i..i + size] { + if v.1[0..size] == input.bytes()[i..i + size] { unsafe { buffer_copy(input.bytes_mut(), &v.0, 0, i, size); } @@ -1100,7 +1100,7 @@ where ) -> Result, Error> { // TODO // handle 128-bits logs - let size = input.bytes_ref().len(); + let size = input.bytes().len(); if size == 0 { return Ok(vec![]); } @@ -1125,9 +1125,9 @@ where let orig_cmpvals = cmp_meta.orig_cmpvals(); let new_cmpvals = cmp_meta.new_cmpvals(); let headers = cmp_meta.headers(); - let input_len = input.bytes_ref().len(); + let input_len = input.bytes().len(); let new_bytes = taint_meta.input_vec(); - let orig_bytes = input.bytes_ref(); + let orig_bytes = input.bytes(); let taint = taint_meta.ranges(); let mut ret = max_count.map_or_else(Vec::new, Vec::with_capacity); diff --git a/libafl/src/mutators/unicode/mod.rs b/libafl/src/mutators/unicode/mod.rs index 39c348cf01..60a7b6cdb0 100644 --- a/libafl/src/mutators/unicode/mod.rs +++ b/libafl/src/mutators/unicode/mod.rs @@ -224,7 +224,7 @@ fn rand_replace_range char>( ) -> MutationResult { let temp_range = rand_range(state, range.end - range.start, MAX_CHARS); let range = (range.start + temp_range.start)..(range.start + temp_range.end); - let range = match core::str::from_utf8(&input.0.bytes_ref()[range.clone()]) { + let range = match core::str::from_utf8(&input.0.bytes()[range.clone()]) { Ok(_) => range, Err(e) => range.start..(range.start + e.valid_up_to()), }; @@ -233,7 +233,7 @@ fn rand_replace_range char>( println!( "mutating range: {:?} ({:?})", range, - core::str::from_utf8(&input.0.bytes_ref()[range.clone()]) + core::str::from_utf8(&input.0.bytes()[range.clone()]) ); if range.start == range.end { return MutationResult::Skipped; @@ -261,7 +261,7 @@ fn rand_replace_range char>( } input.0.splice(range, replacement); - input.1 = extract_metadata(input.0.bytes_ref()); + input.1 = extract_metadata(input.0.bytes()); MutationResult::Mutated } @@ -283,11 +283,11 @@ where S: HasRand + HasMaxSize, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes_ref().is_empty() { + if input.0.bytes().is_empty() { return Ok(MutationResult::Skipped); } - let bytes = input.0.bytes_ref(); + let bytes = input.0.bytes(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -342,11 +342,11 @@ where S: HasRand + HasMaxSize, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes_ref().is_empty() { + if input.0.bytes().is_empty() { return Ok(MutationResult::Skipped); } - let bytes = input.0.bytes_ref(); + let bytes = input.0.bytes(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -389,7 +389,7 @@ where S: HasRand + HasMaxSize + HasMetadata, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes_ref().is_empty() { + if input.0.bytes().is_empty() { return Ok(MutationResult::Skipped); } @@ -404,7 +404,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let bytes = input.0.bytes_ref(); + let bytes = input.0.bytes(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -425,7 +425,7 @@ where } input.0.splice(range, token.iter().copied()); - input.1 = extract_metadata(input.0.bytes_ref()); + input.1 = extract_metadata(input.0.bytes()); return Ok(MutationResult::Mutated); } @@ -449,7 +449,7 @@ where S: HasRand + HasMaxSize + HasMetadata, { fn mutate(&mut self, state: &mut S, input: &mut UnicodeInput) -> Result { - if input.0.bytes_ref().is_empty() { + if input.0.bytes().is_empty() { return Ok(MutationResult::Skipped); } @@ -464,7 +464,7 @@ where }; let token_idx = state.rand_mut().below(tokens_len); - let bytes = input.0.bytes_ref(); + let bytes = input.0.bytes(); let meta = &input.1; if let Some((base, len)) = choose_start(state.rand_mut(), bytes, meta) { let substring = core::str::from_utf8(&bytes[base..][..len])?; @@ -485,7 +485,7 @@ where } input.0.splice(range, token.iter().copied()); - input.1 = extract_metadata(input.0.bytes_ref()); + input.1 = extract_metadata(input.0.bytes()); return Ok(MutationResult::Mutated); } @@ -523,10 +523,10 @@ mod test { )?; for _ in 0..(1 << 12) { - let metadata = extract_metadata(bytes.bytes_ref()); + let metadata = extract_metadata(bytes.bytes()); let mut input = (bytes, metadata); let _ = mutator.mutate(&mut state, &mut input); - println!("{:?}", core::str::from_utf8(input.0.bytes_ref()).unwrap()); + println!("{:?}", core::str::from_utf8(input.0.bytes()).unwrap()); bytes = input.0; } @@ -555,10 +555,10 @@ mod test { )?; for _ in 0..(1 << 12) { - let metadata = extract_metadata(bytes.bytes_ref()); + let metadata = extract_metadata(bytes.bytes()); let mut input = (bytes, metadata); let _ = mutator.mutate(&mut state, &mut input); - println!("{:?}", core::str::from_utf8(input.0.bytes_ref()).unwrap()); + println!("{:?}", core::str::from_utf8(input.0.bytes()).unwrap()); bytes = input.0; } diff --git a/libafl/src/stages/colorization.rs b/libafl/src/stages/colorization.rs index c2712dae25..2beef96087 100644 --- a/libafl/src/stages/colorization.rs +++ b/libafl/src/stages/colorization.rs @@ -228,7 +228,7 @@ where unsafe { buffer_copy( input.bytes_mut(), - changed.bytes_ref(), + changed.bytes(), range_start, range_start, copy_len, @@ -257,7 +257,7 @@ where unsafe { buffer_copy( input.bytes_mut(), - backup.bytes_ref(), + backup.bytes(), range_start, range_start, copy_len, @@ -300,11 +300,11 @@ where } if let Some(meta) = state.metadata_map_mut().get_mut::() { - meta.update(input.bytes_ref().to_vec(), res); + meta.update(input.bytes().to_vec(), res); // println!("meta: {:#?}", meta); } else { - let meta = TaintMetadata::new(input.bytes_ref().to_vec(), res); + let meta = TaintMetadata::new(input.bytes().to_vec(), res); state.add_metadata::(meta); } diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index 14d13c8740..266e880954 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -108,7 +108,7 @@ where let mut entry = state.corpus().get(corpus_id)?.borrow_mut(); let input = entry.input_mut().as_mut().unwrap(); - let payload: Vec<_> = input.bytes_ref().iter().map(|&x| Some(x)).collect(); + let payload: Vec<_> = input.bytes().iter().map(|&x| Some(x)).collect(); let original = input.clone(); let meta = entry.metadata_map().get::().ok_or_else(|| { Error::key_not_found(format!( diff --git a/libafl/src/stages/unicode.rs b/libafl/src/stages/unicode.rs index 9a87e55a96..98957a015c 100644 --- a/libafl/src/stages/unicode.rs +++ b/libafl/src/stages/unicode.rs @@ -119,7 +119,7 @@ where let input = tc.load_input(state.corpus())?; - let bytes = input.bytes_ref(); + let bytes = input.bytes(); let metadata = extract_metadata(bytes); tc.add_metadata(metadata); diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs index d1919232ca..dab8f27433 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/tmin.rs @@ -110,7 +110,7 @@ fn minimize_crash_with_mutator>( } let mut testcase = state.testcase_mut(id)?; - let input = testcase.load_input(state.corpus())?.bytes_ref().to_vec(); + let input = testcase.load_input(state.corpus())?.bytes().to_vec(); drop(testcase); if input.len() >= size { eprintln!( diff --git a/libafl_targets/src/libfuzzer/mutators.rs b/libafl_targets/src/libfuzzer/mutators.rs index 44d3507ee5..71ec0193b0 100644 --- a/libafl_targets/src/libfuzzer/mutators.rs +++ b/libafl_targets/src/libfuzzer/mutators.rs @@ -19,7 +19,7 @@ use libafl::{ state::{HasCorpus, HasMaxSize, HasRand}, Error, }; -use libafl_bolts::{rands::Rand, AsSlice, Named}; +use libafl_bolts::{rands::Rand, AsSlice, HasLen, Named}; extern "C" { fn libafl_targets_has_libfuzzer_custom_mutator() -> bool; @@ -173,7 +173,7 @@ where drop(result); if succeeded { - let target = intermediary.bytes_ref(); + let target = intermediary.bytes(); if target.as_slice().len() > max_size { self.result .replace(Err(Error::illegal_state("Mutation result was too long!"))) @@ -322,7 +322,7 @@ where input: &mut S::Input, ) -> Result { let seed = state.rand_mut().next(); - let len_orig = input.bytes_ref().len(); + let len_orig = input.bytes().len(); let len_max = state.max_size(); input.resize(len_max, 0); @@ -407,7 +407,7 @@ where let mut other_testcase = state.corpus().get_from_all(id)?.borrow_mut(); let other = other_testcase.load_input(state.corpus())?; - let data2 = Vec::from(other.bytes_ref()); + let data2 = Vec::from(other.bytes()); drop(other_testcase); let seed = state.rand_mut().next(); From 83172d4bb380064ff68757a62d856adc9b73ac2a Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Mon, 15 Jul 2024 11:37:54 +0200 Subject: [PATCH 17/27] fix doc --- libafl/src/inputs/bytessub.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index ef681ef201..de8f9b9584 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -36,7 +36,7 @@ where min(end, max_len) } -/// An immutable contiguous subslice of an input implementing [`HasTargetBytes`]. +/// An immutable contiguous subslice of a byte slice. /// It is mostly useful to cheaply wrap a subslice of a given input. /// /// A mutable version is available: [`BytesSubInputMut`]. From d8e07918b2398e08edfbbd043d75d6830aa92bf3 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 17 Jul 2024 14:26:47 +0200 Subject: [PATCH 18/27] mut sub slice version. return subinput to old state, and add subslice stubs --- libafl/src/inputs/bytessub.rs | 286 +++++++++++++++++++--------------- libafl/src/inputs/mod.rs | 11 +- 2 files changed, 168 insertions(+), 129 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index de8f9b9584..0fabbce558 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -1,12 +1,15 @@ -//! [`BytesSubInputMut`] is a wrapper input that can be used to mutate parts of a byte slice +//! [`BytesSubInput`] is a wrapper input that can be used to mutate parts of a byte slice -use alloc::vec::Vec; +use alloc::vec::{self, Vec}; use core::{ cmp::{min, Ordering}, ops::{Bound, Range, RangeBounds}, }; -use libafl_bolts::{ownedref::OwnedSlice, HasLen}; +use libafl_bolts::{ + ownedref::{OwnedMutSlice, OwnedSlice}, + HasLen, +}; use super::HasMutatorBytes; @@ -36,10 +39,50 @@ where min(end, max_len) } +fn sub_range(outer_range: &Range, inner_range: R) -> (Bound, Bound) +where + R: RangeBounds, +{ + let start = + match (outer_range.start_bound(), inner_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 (outer_range.end_bound(), inner_range.end_bound()) { + (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, + (Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound), + (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(outer_range.end - *bound), + (Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound), + (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(outer_range.end - *bound), + (Bound::Included(own), Bound::Included(other)) => { + Bound::Included(min(*own, outer_range.start + other)) + } + (Bound::Included(own), Bound::Excluded(other)) => { + Bound::Included(min(*own, outer_range.start + other - 1)) + } + (Bound::Excluded(own), Bound::Included(other)) => { + Bound::Included(min(*own - 1, outer_range.start + other)) + } + (Bound::Excluded(own), Bound::Excluded(other)) => { + Bound::Excluded(min(*own, outer_range.start + other)) + } + }; + + (start, end) +} + /// An immutable contiguous subslice of a byte slice. /// It is mostly useful to cheaply wrap a subslice of a given input. /// -/// A mutable version is available: [`BytesSubInputMut`]. +/// A mutable version is available: [`BytesSliceMut`]. #[derive(Debug)] pub struct BytesSlice<'a> { /// The (complete) parent input we will work on @@ -48,8 +91,20 @@ pub struct BytesSlice<'a> { range: Range, } +/// A mutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// An immutable version is available: [`BytesSlice`]. +#[derive(Debug)] +pub struct BytesSliceMut<'a> { + /// The (complete) parent input we will work on + parent_slice: OwnedMutSlice<'a, u8>, + /// The range inside the parent input we will work on + range: Range, +} + impl<'a> BytesSlice<'a> { - /// Creates a new [`BytesSubInputMut`] that's a view on an input with mutator bytes. + /// 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(parent_slice: OwnedSlice<'a, u8>, range: R) -> Self where @@ -72,7 +127,7 @@ impl<'a> BytesSlice<'a> { &self.parent_slice[self.range.clone()] } - /// Creates a new [`BytesSubInputMut`] that's a view on an input with mutator bytes. + /// 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 with_slice(parent_slice: &'a [u8], range: R) -> Self where @@ -104,47 +159,77 @@ impl<'a> BytesSlice<'a> { where R: RangeBounds, { - 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), - }; + sub_range(&self.range, range) + } +} - 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)) - } - }; +impl<'a> BytesSliceMut<'a> { + /// Creates a new [`BytesSliceMut`] 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(parent_slice: OwnedMutSlice<'a, u8>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + BytesSliceMut { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } - (start, end) + /// Get the sub slice as bytes. + #[must_use] + pub fn bytes(&self) -> &[u8] { + &self.parent_slice[self.range.clone()] + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn bytes_mut(&mut self) -> &mut [u8] { + &mut self.parent_slice[self.range.clone()] + } + + /// Creates a new [`BytesSliceMut`] 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 with_slice(parent_slice: &'a mut [u8], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(&self) -> OwnedMutSlice<'a, u8> { + self.parent_slice.clone() + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + sub_range(&self.range, range) } } -/// The [`BytesSubInputMut`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on +/// The [`BytesSubInput`] makes it possible to use [`crate::mutators::Mutator`]`s` that work on /// inputs implementing the [`HasMutatorBytes`] for a sub-range of this input. /// For example, we can do the following: /// ```rust @@ -197,21 +282,18 @@ impl<'a> BytesSlice<'a> { /// /// The input supports all methods in the [`HasMutatorBytes`] trait if the parent input also implements this trait. #[derive(Debug)] -pub struct BytesSubInputMut<'a, I> -where - I: HasMutatorBytes + ?Sized, -{ +pub struct BytesSubInput<'a, I: ?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, } -impl<'a, I> BytesSubInputMut<'a, I> +impl<'a, I> BytesSubInput<'a, I> where - I: HasMutatorBytes + ?Sized + HasLen, + I: HasMutatorBytes + ?Sized, { - /// Creates a new [`BytesSubInputMut`] that's a view on an input with mutator bytes. + /// 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(parent_input: &'a mut I, range: R) -> Self where @@ -219,7 +301,7 @@ where { let parent_len = parent_input.len(); - BytesSubInputMut { + BytesSubInput { parent_input, range: Range { start: start_index(&range), @@ -228,64 +310,20 @@ where } } - /// The inclusive start index in the parent buffer - fn start_index(&self) -> usize { - self.range.start + /// Get a [`BytesSlice`] representation of the byte input. + pub fn bytes_slice(&mut self) -> BytesSlice { + BytesSlice::new(self.parent_input.bytes().into(), self.range.clone()) } - /// 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(&self, range: R2) -> (Bound, Bound) - where - R2: RangeBounds, - { - 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) + /// Get a [`BytesSliceMut`] representation of the byte input. + pub fn bytes_slice_mut(&mut self) -> BytesSliceMut { + BytesSliceMut::new(self.parent_input.bytes_mut().into(), self.range.clone()) } } -impl<'a, I> HasMutatorBytes for BytesSubInputMut<'a, I> +impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I> where - I: HasMutatorBytes + HasLen, + I: HasMutatorBytes, { #[inline] fn bytes(&self) -> &[u8] { @@ -298,8 +336,8 @@ where } fn resize(&mut self, new_len: usize, value: u8) { - let start_index = self.start_index(); - let end_index = self.end_index(); + let start_index = self.range.start; + let end_index = self.range.end; let old_len = end_index - start_index; match new_len.cmp(&old_len) { @@ -348,7 +386,7 @@ where } fn extend<'b, IT: IntoIterator>(&mut self, iter: IT) { - let old_len = self.end_index() - self.start_index(); + let old_len = self.len(); let new_values: Vec = iter.into_iter().copied().collect(); self.resize(old_len + new_values.len(), 0); @@ -359,24 +397,21 @@ where /// 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( - &mut self, - range: R2, - replace_with: IT, - ) -> alloc::vec::Splice<'_, IT::IntoIter> + fn splice(&mut self, range: R2, replace_with: IT) -> vec::Splice<'_, IT::IntoIter> where R2: RangeBounds, IT: IntoIterator, { - let range = self.sub_range(range); + let range = sub_range(&self.range, range); self.parent_input.splice(range, replace_with) } - fn drain(&mut self, range: R2) -> alloc::vec::Drain<'_, u8> + fn drain(&mut self, range: R2) -> vec::Drain<'_, u8> where R2: RangeBounds, { - let drain = self.parent_input.drain(self.sub_range(range)); + let sub_range = sub_range(&self.range, range); + let drain = self.parent_input.drain(sub_range); self.range.end -= drain.len(); drain } @@ -389,9 +424,16 @@ impl<'a> HasLen for BytesSlice<'a> { } } -impl<'a, I> HasLen for BytesSubInputMut<'a, I> +impl<'a> HasLen for BytesSliceMut<'a> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, I> HasLen for BytesSubInput<'a, I> where - I: HasMutatorBytes + I: HasMutatorBytes, { #[inline] fn len(&self) -> usize { @@ -559,12 +601,12 @@ mod tests { fn test_ranges_mut() { 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); + assert_eq!(bytes_input.sub_input(..1).bytes_slice().start_index(), 0); + assert_eq!(bytes_input.sub_input(1..=1).bytes_slice().start_index(), 1); + assert_eq!(bytes_input.sub_input(..1).bytes_slice().end_index(), 1); + assert_eq!(bytes_input.sub_input(..=1).bytes_slice().end_index(), 2); + assert_eq!(bytes_input.sub_input(1..=1).bytes_slice().end_index(), 2); + assert_eq!(bytes_input.sub_input(1..).bytes_slice().end_index(), 3); + assert_eq!(bytes_input.sub_input(..3).bytes_slice().end_index(), 3); } } diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 6d31e29557..91156619e6 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::{BytesSlice, BytesSubInputMut}; +pub use bytessub::{BytesSlice, BytesSubInput}; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -265,11 +265,11 @@ pub trait HasMutatorBytes: HasLen { } /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. - fn sub_input(&mut self, range: R) -> BytesSubInputMut + fn sub_input(&mut self, range: R) -> BytesSubInput where R: RangeBounds, { - BytesSubInputMut::new(self, range) + BytesSubInput::new(self, range) } } @@ -435,10 +435,7 @@ mod tests { assert_eq!(*bytes_read.unwrap().bytes(), [3, 4, 5]); let bytes_read = bytes_reader.next_sub_input(8); - assert_eq!( - *bytes_read.unwrap_err().partial().unwrap().bytes(), - [6, 7] - ); + assert_eq!(*bytes_read.unwrap_err().partial().unwrap().bytes(), [6, 7]); let bytes_read = bytes_reader.next_sub_input(8); assert!(bytes_read.unwrap_err().empty()); From bf1d209bf534a20b0c71846813524a523716063c Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Wed, 17 Jul 2024 15:00:31 +0200 Subject: [PATCH 19/27] better api, doc fixes. --- libafl/src/inputs/bytessub.rs | 37 ++++++++++++----------------------- libafl/src/inputs/mod.rs | 15 ++++++++++++-- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 0fabbce558..8d5a5cd272 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -104,8 +104,7 @@ pub struct BytesSliceMut<'a> { } impl<'a> BytesSlice<'a> { - /// 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. + /// Creates a new [`BytesSlice`], a sub-slice representation of a byte array. pub fn new(parent_slice: OwnedSlice<'a, u8>, range: R) -> Self where R: RangeBounds, @@ -127,8 +126,7 @@ impl<'a> BytesSlice<'a> { &self.parent_slice[self.range.clone()] } - /// 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. + /// Creates a new [`BytesSlice`] that's a sliced view on a bytes slice. pub fn with_slice(parent_slice: &'a [u8], range: R) -> Self where R: RangeBounds, @@ -164,8 +162,7 @@ impl<'a> BytesSlice<'a> { } impl<'a> BytesSliceMut<'a> { - /// Creates a new [`BytesSliceMut`] that's a view on an input with mutator bytes. - /// The sub input can then be used to mutate parts of the original input. + /// Creates a new [`BytesSliceMut`], a sub-slice representation of a byte array. pub fn new(parent_slice: OwnedMutSlice<'a, u8>, range: R) -> Self where R: RangeBounds, @@ -193,8 +190,8 @@ impl<'a> BytesSliceMut<'a> { &mut self.parent_slice[self.range.clone()] } - /// Creates a new [`BytesSliceMut`] that's a view on an input with mutator bytes. - /// The sub input can then be used to mutate parts of the original input. + /// Creates a new [`BytesSliceMut`] that's a view on a bytes slice. + /// The sub-slice can then be used to mutate parts of the original bytes. pub fn with_slice(parent_slice: &'a mut [u8], range: R) -> Self where R: RangeBounds, @@ -309,16 +306,6 @@ where }, } } - - /// Get a [`BytesSlice`] representation of the byte input. - pub fn bytes_slice(&mut self) -> BytesSlice { - BytesSlice::new(self.parent_input.bytes().into(), self.range.clone()) - } - - /// Get a [`BytesSliceMut`] representation of the byte input. - pub fn bytes_slice_mut(&mut self) -> BytesSliceMut { - BytesSliceMut::new(self.parent_input.bytes_mut().into(), self.range.clone()) - } } impl<'a, I> HasMutatorBytes for BytesSubInput<'a, I> @@ -601,12 +588,12 @@ mod tests { fn test_ranges_mut() { let mut bytes_input = BytesInput::new(vec![1, 2, 3]); - assert_eq!(bytes_input.sub_input(..1).bytes_slice().start_index(), 0); - assert_eq!(bytes_input.sub_input(1..=1).bytes_slice().start_index(), 1); - assert_eq!(bytes_input.sub_input(..1).bytes_slice().end_index(), 1); - assert_eq!(bytes_input.sub_input(..=1).bytes_slice().end_index(), 2); - assert_eq!(bytes_input.sub_input(1..=1).bytes_slice().end_index(), 2); - assert_eq!(bytes_input.sub_input(1..).bytes_slice().end_index(), 3); - assert_eq!(bytes_input.sub_input(..3).bytes_slice().end_index(), 3); + assert_eq!(bytes_input.sub_bytes_mut(..1).start_index(), 0); + assert_eq!(bytes_input.sub_bytes_mut(1..=1).start_index(), 1); + assert_eq!(bytes_input.sub_bytes_mut(..1).end_index(), 1); + assert_eq!(bytes_input.sub_bytes_mut(..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes_mut(1..=1).end_index(), 2); + assert_eq!(bytes_input.sub_bytes_mut(1..).end_index(), 3); + assert_eq!(bytes_input.sub_bytes_mut(..3).end_index(), 3); } } diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 91156619e6..61bec2af04 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -34,12 +34,15 @@ use std::{fs::File, hash::Hash, io::Read, path::Path}; #[cfg(feature = "std")] use libafl_bolts::fs::write_file_atomic; -use libafl_bolts::{ownedref::OwnedSlice, Error, HasLen}; +use libafl_bolts::{ + ownedref::{OwnedMutSlice, OwnedSlice}, + Error, HasLen, +}; #[cfg(feature = "nautilus")] pub use nautilus::*; use serde::{Deserialize, Serialize}; -use crate::corpus::CorpusId; +use crate::{corpus::CorpusId, inputs::bytessub::BytesSliceMut}; /// An input for the target #[cfg(not(feature = "std"))] @@ -264,6 +267,14 @@ pub trait HasMutatorBytes: HasLen { BytesSlice::new(OwnedSlice::from(self.bytes()), range) } + /// Creates a [`BytesSliceMut`] from this input, that can be used to slice a byte array. + fn sub_bytes_mut(&mut self, range: R) -> BytesSliceMut + where + R: RangeBounds, + { + BytesSliceMut::new(OwnedMutSlice::from(self.bytes_mut()), range) + } + /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. fn sub_input(&mut self, range: R) -> BytesSubInput where From d111e9ef205022499354efe74d04a914166b5aa3 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 18 Jul 2024 21:57:14 +0200 Subject: [PATCH 20/27] Don't clone, reshuffle --- libafl/src/inputs/bytessub.rs | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 8d5a5cd272..41fdb569e4 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -11,7 +11,7 @@ use libafl_bolts::{ HasLen, }; -use super::HasMutatorBytes; +use crate::inputs::HasMutatorBytes; /// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) fn start_index(range: &R) -> usize @@ -91,16 +91,11 @@ pub struct BytesSlice<'a> { range: Range, } -/// A mutable contiguous subslice of a byte slice. -/// It is mostly useful to cheaply wrap a subslice of a given input. -/// -/// An immutable version is available: [`BytesSlice`]. -#[derive(Debug)] -pub struct BytesSliceMut<'a> { - /// The (complete) parent input we will work on - parent_slice: OwnedMutSlice<'a, u8>, - /// The range inside the parent input we will work on - range: Range, +impl<'a> HasLen for BytesSlice<'a> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } } impl<'a> BytesSlice<'a> { @@ -136,8 +131,8 @@ impl<'a> BytesSlice<'a> { /// The parent input #[must_use] - pub fn parent_slice(&self) -> OwnedSlice<'a, u8> { - self.parent_slice.clone() + pub fn parent_slice(self) -> OwnedSlice<'a, u8> { + self.parent_slice } /// The inclusive start index in the parent buffer @@ -161,6 +156,18 @@ impl<'a> BytesSlice<'a> { } } +/// A mutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// An immutable version is available: [`BytesSlice`]. +#[derive(Debug)] +pub struct BytesSliceMut<'a> { + /// The (complete) parent input we will work on + parent_slice: OwnedMutSlice<'a, u8>, + /// The range inside the parent input we will work on + range: Range, +} + impl<'a> BytesSliceMut<'a> { /// Creates a new [`BytesSliceMut`], a sub-slice representation of a byte array. pub fn new(parent_slice: OwnedMutSlice<'a, u8>, range: R) -> Self @@ -201,8 +208,8 @@ impl<'a> BytesSliceMut<'a> { /// The parent input #[must_use] - pub fn parent_slice(&self) -> OwnedMutSlice<'a, u8> { - self.parent_slice.clone() + pub fn parent_slice(self) -> OwnedMutSlice<'a, u8> { + self.parent_slice } /// The inclusive start index in the parent buffer @@ -226,6 +233,13 @@ impl<'a> BytesSliceMut<'a> { } } +impl<'a> HasLen for BytesSliceMut<'a> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + /// 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: @@ -404,20 +418,6 @@ where } } -impl<'a> HasLen for BytesSlice<'a> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - -impl<'a> HasLen for BytesSliceMut<'a> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - impl<'a, I> HasLen for BytesSubInput<'a, I> where I: HasMutatorBytes, From 13716463cc3d59757354aabe78a695a21c62dc40 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 18 Jul 2024 22:48:48 +0200 Subject: [PATCH 21/27] Move and rename --- libafl/src/inputs/bytessub.rs | 233 +--------------------------------- libafl_bolts/src/lib.rs | 1 + 2 files changed, 4 insertions(+), 230 deletions(-) diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index 41fdb569e4..aad4a02e2e 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -2,244 +2,17 @@ use alloc::vec::{self, Vec}; use core::{ - cmp::{min, Ordering}, - ops::{Bound, Range, RangeBounds}, + cmp::Ordering, + ops::{Range, RangeBounds}, }; use libafl_bolts::{ - ownedref::{OwnedMutSlice, OwnedSlice}, + subrange::{end_index, start_index, sub_range}, HasLen, }; use crate::inputs::HasMutatorBytes; -/// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) -fn start_index(range: &R) -> usize -where - R: RangeBounds, -{ - 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(range: &R, max_len: usize) -> usize -where - R: RangeBounds, -{ - let end = match range.end_bound() { - Bound::Unbounded => max_len, - Bound::Included(end) => end + 1, - Bound::Excluded(end) => *end, - }; - - min(end, max_len) -} - -fn sub_range(outer_range: &Range, inner_range: R) -> (Bound, Bound) -where - R: RangeBounds, -{ - let start = - match (outer_range.start_bound(), inner_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 (outer_range.end_bound(), inner_range.end_bound()) { - (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, - (Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound), - (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(outer_range.end - *bound), - (Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound), - (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(outer_range.end - *bound), - (Bound::Included(own), Bound::Included(other)) => { - Bound::Included(min(*own, outer_range.start + other)) - } - (Bound::Included(own), Bound::Excluded(other)) => { - Bound::Included(min(*own, outer_range.start + other - 1)) - } - (Bound::Excluded(own), Bound::Included(other)) => { - Bound::Included(min(*own - 1, outer_range.start + other)) - } - (Bound::Excluded(own), Bound::Excluded(other)) => { - Bound::Excluded(min(*own, outer_range.start + other)) - } - }; - - (start, end) -} - -/// An immutable contiguous subslice of a byte slice. -/// It is mostly useful to cheaply wrap a subslice of a given input. -/// -/// A mutable version is available: [`BytesSliceMut`]. -#[derive(Debug)] -pub struct BytesSlice<'a> { - /// The (complete) parent input we will work on - parent_slice: OwnedSlice<'a, u8>, - /// The range inside the parent input we will work on - range: Range, -} - -impl<'a> HasLen for BytesSlice<'a> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - -impl<'a> BytesSlice<'a> { - /// Creates a new [`BytesSlice`], a sub-slice representation of a byte array. - pub fn new(parent_slice: OwnedSlice<'a, u8>, range: R) -> Self - where - R: RangeBounds, - { - let parent_len = parent_slice.len(); - - BytesSlice { - parent_slice, - range: Range { - start: start_index(&range), - end: end_index(&range, parent_len), - }, - } - } - - /// Get the sub slice as bytes. - #[must_use] - pub fn bytes(&self) -> &[u8] { - &self.parent_slice[self.range.clone()] - } - - /// Creates a new [`BytesSlice`] that's a sliced view on a bytes slice. - pub fn with_slice(parent_slice: &'a [u8], range: R) -> Self - where - R: RangeBounds, - { - Self::new(parent_slice.into(), range) - } - - /// The parent input - #[must_use] - pub fn parent_slice(self) -> OwnedSlice<'a, u8> { - self.parent_slice - } - - /// The inclusive start index in the parent buffer - #[must_use] - pub fn start_index(&self) -> usize { - self.range.start - } - - /// The exclusive end index in the parent buffer - #[must_use] - pub fn end_index(&self) -> usize { - self.range.end - } - - /// Creates a sub range in the current own range - pub fn sub_range(&self, range: R) -> (Bound, Bound) - where - R: RangeBounds, - { - sub_range(&self.range, range) - } -} - -/// A mutable contiguous subslice of a byte slice. -/// It is mostly useful to cheaply wrap a subslice of a given input. -/// -/// An immutable version is available: [`BytesSlice`]. -#[derive(Debug)] -pub struct BytesSliceMut<'a> { - /// The (complete) parent input we will work on - parent_slice: OwnedMutSlice<'a, u8>, - /// The range inside the parent input we will work on - range: Range, -} - -impl<'a> BytesSliceMut<'a> { - /// Creates a new [`BytesSliceMut`], a sub-slice representation of a byte array. - pub fn new(parent_slice: OwnedMutSlice<'a, u8>, range: R) -> Self - where - R: RangeBounds, - { - let parent_len = parent_slice.len(); - - BytesSliceMut { - parent_slice, - range: Range { - start: start_index(&range), - end: end_index(&range, parent_len), - }, - } - } - - /// Get the sub slice as bytes. - #[must_use] - pub fn bytes(&self) -> &[u8] { - &self.parent_slice[self.range.clone()] - } - - /// Get the sub slice as bytes. - #[must_use] - pub fn bytes_mut(&mut self) -> &mut [u8] { - &mut self.parent_slice[self.range.clone()] - } - - /// Creates a new [`BytesSliceMut`] that's a view on a bytes slice. - /// The sub-slice can then be used to mutate parts of the original bytes. - pub fn with_slice(parent_slice: &'a mut [u8], range: R) -> Self - where - R: RangeBounds, - { - Self::new(parent_slice.into(), range) - } - - /// The parent input - #[must_use] - pub fn parent_slice(self) -> OwnedMutSlice<'a, u8> { - self.parent_slice - } - - /// The inclusive start index in the parent buffer - #[must_use] - pub fn start_index(&self) -> usize { - self.range.start - } - - /// The exclusive end index in the parent buffer - #[must_use] - pub fn end_index(&self) -> usize { - self.range.end - } - - /// Creates a sub range in the current own range - pub fn sub_range(&self, range: R) -> (Bound, Bound) - where - R: RangeBounds, - { - sub_range(&self.range, range) - } -} - -impl<'a> HasLen for BytesSliceMut<'a> { - #[inline] - fn len(&self) -> usize { - self.range.len() - } -} - /// 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: diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index f8b4ea0bea..cb7f81afea 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -131,6 +131,7 @@ pub mod serdeany; pub mod shmem; #[cfg(feature = "std")] pub mod staterestore; +pub mod subrange; // TODO: reenable once ahash works in no-alloc #[cfg(any(feature = "xxh3", feature = "alloc"))] pub mod tuples; From 2bbf4efa0c6323746b73d1aefacceae801773862 Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 18 Jul 2024 22:58:50 +0200 Subject: [PATCH 22/27] Uh-oh --- libafl/src/inputs/mod.rs | 67 +++++++++++++--------------------------- 1 file changed, 21 insertions(+), 46 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 61bec2af04..6ac4e85245 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -13,7 +13,7 @@ pub mod generalized; pub use generalized::*; pub mod bytessub; -pub use bytessub::{BytesSlice, BytesSubInput}; +pub use bytessub::BytesSubInput; #[cfg(feature = "multipart_inputs")] pub mod multi; @@ -36,13 +36,14 @@ use std::{fs::File, hash::Hash, io::Read, path::Path}; use libafl_bolts::fs::write_file_atomic; use libafl_bolts::{ ownedref::{OwnedMutSlice, OwnedSlice}, + subrange::{PartialSubRangeSlice, SubRangeSlice, SubRangeSliceMut}, Error, HasLen, }; #[cfg(feature = "nautilus")] pub use nautilus::*; use serde::{Deserialize, Serialize}; -use crate::{corpus::CorpusId, inputs::bytessub::BytesSliceMut}; +use crate::corpus::CorpusId; /// An input for the target #[cfg(not(feature = "std"))] @@ -140,35 +141,6 @@ pub struct BytesReader<'a> { pos: usize, } -/// Representation of a partial slice -/// This is used when providing a slice smaller than the expected one. -/// It notably happens when trying to read the end of an input. -#[derive(Debug)] -pub enum PartialBytesSubInput<'a> { - /// The slice is empty, and thus not kept - Empty, - /// The slice is strictly smaller than the expected one. - Partial(BytesSlice<'a>), -} - -impl<'a> PartialBytesSubInput<'a> { - /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. - #[must_use] - pub fn empty(self) -> bool { - matches!(self, PartialBytesSubInput::Empty) - } - - /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. - #[must_use] - pub fn partial(self) -> Option> { - #[allow(clippy::match_wildcard_for_single_variants)] - match self { - PartialBytesSubInput::Partial(partial_slice) => Some(partial_slice), - _ => None, - } - } -} - impl<'a> BytesReader<'a> { /// Create a new [`BytesReader`]. /// The position of the reader is initialized to 0. @@ -184,8 +156,8 @@ impl<'a> BytesReader<'a> { /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. /// This function does not provide any feedback on whether the slice was cropped or not. #[must_use] - pub fn next_sub_slice_truncated(&mut self, limit: usize) -> BytesSlice<'a> { - let sub_input = BytesSlice::with_slice(self.parent_input, self.pos..(self.pos + limit)); + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> PartialSubRangeSlice<'a, u8> { + let sub_input = SubRangeSlice::with_slice(self.parent_input, self.pos..(self.pos + limit)); self.pos += sub_input.len(); @@ -201,15 +173,15 @@ impl<'a> BytesReader<'a> { pub fn next_sub_input( &mut self, limit: usize, - ) -> Result, PartialBytesSubInput<'a>> { + ) -> Result, PartialSubRangeSlice<'a, u8>> { let slice_to_return = self.next_sub_slice_truncated(limit); let real_len = slice_to_return.len(); if real_len == 0 { - Err(PartialBytesSubInput::Empty) + Err(PartialSubRangeSlice::Empty) } else if real_len < limit { - Err(PartialBytesSubInput::Partial(slice_to_return)) + Err(PartialSubRangeSlice::Partial(slice_to_return)) } else { Ok(slice_to_return) } @@ -260,15 +232,15 @@ pub trait HasMutatorBytes: HasLen { R: RangeBounds; /// Creates a [`BytesSlice`] from this input, that can be used to slice a byte array. - fn sub_bytes(&self, range: R) -> BytesSlice + fn sub_bytes(&self, range: R) -> SubRangeSlice<'a, u8> where R: RangeBounds, { - BytesSlice::new(OwnedSlice::from(self.bytes()), range) + SubRangeSlice::new(OwnedSlice::from(self.bytes()), range) } /// Creates a [`BytesSliceMut`] from this input, that can be used to slice a byte array. - fn sub_bytes_mut(&mut self, range: R) -> BytesSliceMut + fn sub_bytes_mut(&mut self, range: R) -> SubRangeSliceMut<'a, u8> where R: RangeBounds, { @@ -421,17 +393,17 @@ mod tests { let mut bytes_reader = BytesReader::new(&bytes_input); let bytes_read = bytes_reader.next_sub_slice_truncated(2); - assert_eq!(*bytes_read.bytes(), [1, 2]); + assert_eq!(*bytes_read.as_slice(), [1, 2]); let bytes_read = bytes_reader.next_sub_slice_truncated(3); - assert_eq!(*bytes_read.bytes(), [3, 4, 5]); + assert_eq!(*bytes_read.as_slice(), [3, 4, 5]); let bytes_read = bytes_reader.next_sub_slice_truncated(8); - assert_eq!(*bytes_read.bytes(), [6, 7]); + assert_eq!(*bytes_read.as_slice(), [6, 7]); let bytes_read = bytes_reader.next_sub_slice_truncated(8); let bytes_read_ref: &[u8] = &[]; - assert_eq!(&*bytes_read.bytes(), bytes_read_ref); + assert_eq!(&*bytes_read.as_slice(), bytes_read_ref); } #[test] @@ -440,13 +412,16 @@ mod tests { let mut bytes_reader = BytesReader::new(&bytes_input); let bytes_read = bytes_reader.next_sub_input(2); - assert_eq!(*bytes_read.unwrap().bytes(), [1, 2]); + assert_eq!(*bytes_read.unwrap().as_slice(), [1, 2]); let bytes_read = bytes_reader.next_sub_input(3); - assert_eq!(*bytes_read.unwrap().bytes(), [3, 4, 5]); + assert_eq!(*bytes_read.unwrap().as_slice(), [3, 4, 5]); let bytes_read = bytes_reader.next_sub_input(8); - assert_eq!(*bytes_read.unwrap_err().partial().unwrap().bytes(), [6, 7]); + assert_eq!( + *bytes_read.unwrap_err().partial().unwrap().as_slice(), + [6, 7] + ); let bytes_read = bytes_reader.next_sub_input(8); assert!(bytes_read.unwrap_err().empty()); From da2d4c60844c40e1ee91e50fc3c2e45476a42e41 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Fri, 19 Jul 2024 13:49:24 +0200 Subject: [PATCH 23/27] move to bolts. rename things. --- libafl/src/inputs/bytessub.rs | 6 +- libafl/src/inputs/mod.rs | 113 +--------- libafl_bolts/src/lib.rs | 4 +- libafl_bolts/src/subrange.rs | 373 ++++++++++++++++++++++++++++++++++ 4 files changed, 382 insertions(+), 114 deletions(-) create mode 100644 libafl_bolts/src/subrange.rs diff --git a/libafl/src/inputs/bytessub.rs b/libafl/src/inputs/bytessub.rs index aad4a02e2e..aaf8f5a9a7 100644 --- a/libafl/src/inputs/bytessub.rs +++ b/libafl/src/inputs/bytessub.rs @@ -225,13 +225,13 @@ mod tests { let (bytes_input, _) = init_bytes_input(); let sub_input = bytes_input.sub_bytes(0..1); - assert_eq!(*sub_input.bytes(), [1]); + assert_eq!(*sub_input.as_slice(), [1]); let sub_input = bytes_input.sub_bytes(1..=2); - assert_eq!(*sub_input.bytes(), [2, 3]); + assert_eq!(*sub_input.as_slice(), [2, 3]); let sub_input = bytes_input.sub_bytes(..); - assert_eq!(*sub_input.bytes(), [1, 2, 3, 4, 5, 6, 7]); + assert_eq!(*sub_input.as_slice(), [1, 2, 3, 4, 5, 6, 7]); } #[test] diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 6ac4e85245..25ee62396e 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -36,7 +36,7 @@ use std::{fs::File, hash::Hash, io::Read, path::Path}; use libafl_bolts::fs::write_file_atomic; use libafl_bolts::{ ownedref::{OwnedMutSlice, OwnedSlice}, - subrange::{PartialSubRangeSlice, SubRangeSlice, SubRangeSliceMut}, + subrange::{SubRangeSlice, SubRangeMutSlice}, Error, HasLen, }; #[cfg(feature = "nautilus")] @@ -133,67 +133,6 @@ impl HasLen for NopInput { } } -/// Target bytes wrapper keeping track of the current read position. -/// Convenient wrapper when bytes must be split in multiple subinputs. -#[derive(Debug)] -pub struct BytesReader<'a> { - parent_input: &'a [u8], - pos: usize, -} - -impl<'a> BytesReader<'a> { - /// Create a new [`BytesReader`]. - /// The position of the reader is initialized to 0. - #[must_use] - pub fn new(input: &'a [u8]) -> Self { - Self { - parent_input: input, - pos: 0, - } - } - - /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. - /// If the resulting slice would go beyond the end of the parent input, it will be truncated to the length of the parent input. - /// This function does not provide any feedback on whether the slice was cropped or not. - #[must_use] - pub fn next_sub_slice_truncated(&mut self, limit: usize) -> PartialSubRangeSlice<'a, u8> { - let sub_input = SubRangeSlice::with_slice(self.parent_input, self.pos..(self.pos + limit)); - - self.pos += sub_input.len(); - - sub_input - } - - /// Read an immutable subinput from the parent input, from the current cursor position up to `limit` bytes. - /// If the resulting slice would go beyond the end of the parent input, it will be limited to the length of the parent input. - /// The function returns - /// - `Ok(Slice)` if the returned slice has `limit` bytes. - /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` bytes and is not empty. - /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. - pub fn next_sub_input( - &mut self, - limit: usize, - ) -> Result, PartialSubRangeSlice<'a, u8>> { - let slice_to_return = self.next_sub_slice_truncated(limit); - - let real_len = slice_to_return.len(); - - if real_len == 0 { - Err(PartialSubRangeSlice::Empty) - } else if real_len < limit { - Err(PartialSubRangeSlice::Partial(slice_to_return)) - } else { - Ok(slice_to_return) - } - } -} - -impl<'a> From<&'a [u8]> for BytesReader<'a> { - fn from(input: &'a [u8]) -> Self { - Self::new(input) - } -} - // TODO change this to fn target_bytes(&self, buffer: &mut Vec) -> &[u8]; /// Has a byte representation intended for the target. /// Can be represented with a vector of bytes. @@ -232,7 +171,7 @@ pub trait HasMutatorBytes: HasLen { R: RangeBounds; /// Creates a [`BytesSlice`] from this input, that can be used to slice a byte array. - fn sub_bytes(&self, range: R) -> SubRangeSlice<'a, u8> + fn sub_bytes(&self, range: R) -> SubRangeSlice where R: RangeBounds, { @@ -240,11 +179,11 @@ pub trait HasMutatorBytes: HasLen { } /// Creates a [`BytesSliceMut`] from this input, that can be used to slice a byte array. - fn sub_bytes_mut(&mut self, range: R) -> SubRangeSliceMut<'a, u8> + fn sub_bytes_mut(&mut self, range: R) -> SubRangeMutSlice where R: RangeBounds, { - BytesSliceMut::new(OwnedMutSlice::from(self.bytes_mut()), range) + SubRangeMutSlice::new(OwnedMutSlice::from(self.bytes_mut()), range) } /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. @@ -383,47 +322,3 @@ where } } -#[cfg(test)] -mod tests { - use crate::inputs::BytesReader; - - #[test] - fn test_bytesreader_toslice_unchecked() { - let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; - let mut bytes_reader = BytesReader::new(&bytes_input); - - let bytes_read = bytes_reader.next_sub_slice_truncated(2); - assert_eq!(*bytes_read.as_slice(), [1, 2]); - - let bytes_read = bytes_reader.next_sub_slice_truncated(3); - assert_eq!(*bytes_read.as_slice(), [3, 4, 5]); - - let bytes_read = bytes_reader.next_sub_slice_truncated(8); - assert_eq!(*bytes_read.as_slice(), [6, 7]); - - let bytes_read = bytes_reader.next_sub_slice_truncated(8); - let bytes_read_ref: &[u8] = &[]; - assert_eq!(&*bytes_read.as_slice(), bytes_read_ref); - } - - #[test] - fn test_bytesreader_toslice() { - let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; - let mut bytes_reader = BytesReader::new(&bytes_input); - - let bytes_read = bytes_reader.next_sub_input(2); - assert_eq!(*bytes_read.unwrap().as_slice(), [1, 2]); - - let bytes_read = bytes_reader.next_sub_input(3); - assert_eq!(*bytes_read.unwrap().as_slice(), [3, 4, 5]); - - let bytes_read = bytes_reader.next_sub_input(8); - assert_eq!( - *bytes_read.unwrap_err().partial().unwrap().as_slice(), - [6, 7] - ); - - let bytes_read = bytes_reader.next_sub_input(8); - assert!(bytes_read.unwrap_err().empty()); - } -} diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index cb7f81afea..39eff0b6ad 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -310,7 +310,7 @@ pub enum Error { Unsupported(String, ErrorBacktrace), /// Shutting down, not really an error. ShuttingDown, - /// OS error, wrapping a [`std::io::Error`] + /// OS error, wrapping a [`io::Error`] #[cfg(feature = "std")] OsError(io::Error, String, ErrorBacktrace), /// Something else happened @@ -412,7 +412,7 @@ impl Error { { Error::OsError(err, msg.into(), ErrorBacktrace::new()) } - /// OS error from [`std::io::Error::last_os_error`] with additional message + /// OS error from [`io::Error::last_os_error`] with additional message #[cfg(feature = "std")] #[must_use] pub fn last_os_error(msg: S) -> Self diff --git a/libafl_bolts/src/subrange.rs b/libafl_bolts/src/subrange.rs new file mode 100644 index 0000000000..4d43d8d5cd --- /dev/null +++ b/libafl_bolts/src/subrange.rs @@ -0,0 +1,373 @@ +//! Subrange of things. +//! Convenient wrappers to handle sub-slices efficiently. + +use std::cmp::min; +use std::collections::Bound; +use std::ops::{Range, RangeBounds}; +use crate::HasLen; +use crate::ownedref::{OwnedMutSlice, OwnedSlice}; + +/// An immutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// A mutable version is available: [`SubRangeMutSlice`]. +#[derive(Debug)] +pub struct SubRangeSlice<'a, T> { + /// The (complete) parent input we will work on + parent_slice: OwnedSlice<'a, T>, + /// The range inside the parent input we will work on + range: Range, +} + +/// A mutable contiguous subslice of a byte slice. +/// It is mostly useful to cheaply wrap a subslice of a given input. +/// +/// An immutable version is available: [`SubRangeSlice`]. +#[derive(Debug)] +pub struct SubRangeMutSlice<'a, T> { + /// The (complete) parent input we will work on + parent_slice: OwnedMutSlice<'a, T>, + /// The range inside the parent input we will work on + range: Range, +} + +/// Slice wrapper keeping track of the current read position. +/// Convenient wrapper when the slice must be split in multiple sub-slices and read sequentially. +#[derive(Debug)] +pub struct SliceReader<'a, T> { + parent_slice: &'a [T], + pos: usize, +} + +impl<'a, T> SliceReader<'a, T> { + /// Create a new [`SliceReader`]. + /// The position of the reader is initialized to 0. + #[must_use] + pub fn new(parent_slice: &'a [T]) -> Self { + Self { + parent_slice, + pos: 0, + } + } + + /// Read an immutable sub-slice from the parent slice, from the current cursor position up to `limit` elements. + /// If the resulting slice would go beyond the end of the parent slice, it will be truncated to the length of the parent slice. + /// This function does not provide any feedback on whether the slice was cropped or not. + #[must_use] + pub fn next_sub_slice_truncated(&mut self, limit: usize) -> SubRangeSlice<'a, T> { + let sub_slice = SubRangeSlice::with_slice(self.parent_slice, self.pos..(self.pos + limit)); + + self.pos += sub_slice.len(); + + sub_slice + } + + /// Read an immutable sub-slice from the parent slice, from the current cursor position up to `limit` bytes. + /// If the resulting slice would go beyond the end of the parent slice, it will be limited to the length of the parent slice. + /// The function returns + /// - `Ok(Slice)` if the returned slice has `limit` elements. + /// - `Err(Partial(slice))` if the returned slice has strictly less than `limit` elements and is not empty. + /// - `Err(Empty)` if the reader was already at the end or `limit` equals zero. + pub fn next_sub_input( + &mut self, + limit: usize, + ) -> Result, PartialSubRangeSlice<'a, T>> { + let slice_to_return = self.next_sub_slice_truncated(limit); + + let real_len = slice_to_return.len(); + + if real_len == 0 { + Err(PartialSubRangeSlice::Empty) + } else if real_len < limit { + Err(PartialSubRangeSlice::Partial(slice_to_return)) + } else { + Ok(slice_to_return) + } + } +} + +impl<'a, T> From<&'a [T]> for SliceReader<'a, T> { + fn from(input: &'a [T]) -> Self { + Self::new(input) + } +} + +impl<'a, T> HasLen for SubRangeSlice<'a, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + +impl<'a, T> HasLen for SubRangeMutSlice<'a, T> { + #[inline] + fn len(&self) -> usize { + self.range.len() + } +} + + + +/// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) +pub fn start_index(range: &R) -> usize +where + R: RangeBounds, +{ + 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) +pub fn end_index(range: &R, max_len: usize) -> usize +where + R: RangeBounds, +{ + let end = match range.end_bound() { + Bound::Unbounded => max_len, + Bound::Included(end) => end + 1, + Bound::Excluded(end) => *end, + }; + + min(end, max_len) +} + +/// Gets the relevant subrange of a [`Range`] from [`RangeBounds`]. +pub fn sub_range(outer_range: &Range, inner_range: R) -> (Bound, Bound) +where + R: RangeBounds, +{ + let start = + match (outer_range.start_bound(), inner_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 (outer_range.end_bound(), inner_range.end_bound()) { + (Bound::Unbounded, Bound::Unbounded) => Bound::Unbounded, + (Bound::Excluded(bound), Bound::Unbounded) => Bound::Excluded(*bound), + (Bound::Unbounded, Bound::Excluded(bound)) => Bound::Excluded(outer_range.end - *bound), + (Bound::Included(bound), Bound::Unbounded) => Bound::Included(*bound), + (Bound::Unbounded, Bound::Included(bound)) => Bound::Included(outer_range.end - *bound), + (Bound::Included(own), Bound::Included(other)) => { + Bound::Included(min(*own, outer_range.start + other)) + } + (Bound::Included(own), Bound::Excluded(other)) => { + Bound::Included(min(*own, outer_range.start + other - 1)) + } + (Bound::Excluded(own), Bound::Included(other)) => { + Bound::Included(min(*own - 1, outer_range.start + other)) + } + (Bound::Excluded(own), Bound::Excluded(other)) => { + Bound::Excluded(min(*own, outer_range.start + other)) + } + }; + + (start, end) +} + +/// Representation of a partial slice +/// This is used when providing a slice smaller than the expected one. +/// It notably happens when trying to read the end of an input. +#[derive(Debug)] +pub enum PartialSubRangeSlice<'a, T> { + /// The slice is empty, and thus not kept + Empty, + /// The slice is strictly smaller than the expected one. + Partial(SubRangeSlice<'a, T>), +} + +impl<'a, T> PartialSubRangeSlice<'a, T> { + /// Consumes `PartialBytesSubInput` and returns true if it was empty, false otherwise. + #[must_use] + pub fn empty(self) -> bool { + matches!(self, PartialSubRangeSlice::Empty) + } + + /// Consumes `PartialBytesSubInput` and returns the partial slice if it was a partial slice, None otherwise. + #[must_use] + pub fn partial(self) -> Option> { + #[allow(clippy::match_wildcard_for_single_variants)] + match self { + PartialSubRangeSlice::Partial(partial_slice) => Some(partial_slice), + _ => None, + } + } +} + +impl<'a, T> SubRangeSlice<'a, T> { + /// Creates a new [`SubRangeSlice`], a sub-slice representation of a byte array. + pub fn new(parent_slice: OwnedSlice<'a, T>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + SubRangeSlice { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice(&self) -> &[T] { + &self.parent_slice[self.range.clone()] + } + + /// Creates a new [`SubRangeSlice`] that's a sliced view on a bytes slice. + pub fn with_slice(parent_slice: &'a [T], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(self) -> OwnedSlice<'a, T> { + self.parent_slice + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + sub_range(&self.range, range) + } +} + +impl<'a, T> SubRangeMutSlice<'a, T> { + /// Creates a new [`SubRangeMutSlice`], a sub-slice representation of a byte array. + pub fn new(parent_slice: OwnedMutSlice<'a, T>, range: R) -> Self + where + R: RangeBounds, + { + let parent_len = parent_slice.len(); + + SubRangeMutSlice { + parent_slice, + range: Range { + start: start_index(&range), + end: end_index(&range, parent_len), + }, + } + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice(&self) -> &[T] { + &self.parent_slice[self.range.clone()] + } + + /// Get the sub slice as bytes. + #[must_use] + pub fn as_slice_mut(&mut self) -> &mut [T] { + &mut self.parent_slice[self.range.clone()] + } + + /// Creates a new [`SubRangeMutSlice`] that's a view on a bytes slice. + /// The sub-slice can then be used to mutate parts of the original bytes. + pub fn with_slice(parent_slice: &'a mut [T], range: R) -> Self + where + R: RangeBounds, + { + Self::new(parent_slice.into(), range) + } + + /// The parent input + #[must_use] + pub fn parent_slice(self) -> OwnedMutSlice<'a, T> { + self.parent_slice + } + + /// The inclusive start index in the parent buffer + #[must_use] + pub fn start_index(&self) -> usize { + self.range.start + } + + /// The exclusive end index in the parent buffer + #[must_use] + pub fn end_index(&self) -> usize { + self.range.end + } + + /// Creates a sub range in the current own range + pub fn sub_range(&self, range: R) -> (Bound, Bound) + where + R: RangeBounds, + { + sub_range(&self.range, range) + } +} + +#[cfg(test)] +mod tests { + use super::SliceReader; + + #[test] + fn test_bytesreader_toslice_unchecked() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = SliceReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_slice_truncated(2); + assert_eq!(*bytes_read.as_slice(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(3); + assert_eq!(*bytes_read.as_slice(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + assert_eq!(*bytes_read.as_slice(), [6, 7]); + + let bytes_read = bytes_reader.next_sub_slice_truncated(8); + let bytes_read_ref: &[u8] = &[]; + assert_eq!(&*bytes_read.as_slice(), bytes_read_ref); + } + + #[test] + fn test_bytesreader_toslice() { + let bytes_input = vec![1, 2, 3, 4, 5, 6, 7]; + let mut bytes_reader = SliceReader::new(&bytes_input); + + let bytes_read = bytes_reader.next_sub_input(2); + assert_eq!(*bytes_read.unwrap().as_slice(), [1, 2]); + + let bytes_read = bytes_reader.next_sub_input(3); + assert_eq!(*bytes_read.unwrap().as_slice(), [3, 4, 5]); + + let bytes_read = bytes_reader.next_sub_input(8); + assert_eq!( + *bytes_read.unwrap_err().partial().unwrap().as_slice(), + [6, 7] + ); + + let bytes_read = bytes_reader.next_sub_input(8); + assert!(bytes_read.unwrap_err().empty()); + } +} From d37c630672ca06ccfe6ff945fce4c70bac4f9497 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Fri, 19 Jul 2024 13:57:05 +0200 Subject: [PATCH 24/27] nostd --- libafl_bolts/src/rands/mod.rs | 5 ++++- libafl_bolts/src/subrange.rs | 5 ++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/libafl_bolts/src/rands/mod.rs b/libafl_bolts/src/rands/mod.rs index e7516e8358..29140581fd 100644 --- a/libafl_bolts/src/rands/mod.rs +++ b/libafl_bolts/src/rands/mod.rs @@ -3,11 +3,14 @@ use core::{ debug_assert, fmt::Debug, - sync::atomic::{AtomicUsize, Ordering}, + sync::atomic::AtomicUsize, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; +#[cfg(target_has_atomic = "ptr")] +use core::sync::atomic::Ordering; + #[cfg(feature = "alloc")] pub mod loaded_dice; diff --git a/libafl_bolts/src/subrange.rs b/libafl_bolts/src/subrange.rs index 4d43d8d5cd..c470a153c2 100644 --- a/libafl_bolts/src/subrange.rs +++ b/libafl_bolts/src/subrange.rs @@ -1,9 +1,8 @@ //! Subrange of things. //! Convenient wrappers to handle sub-slices efficiently. -use std::cmp::min; -use std::collections::Bound; -use std::ops::{Range, RangeBounds}; +use core::cmp::min; +use core::ops::{Range, RangeBounds, Bound}; use crate::HasLen; use crate::ownedref::{OwnedMutSlice, OwnedSlice}; From 8d3c447a66b58bbbaa6e8e1ecd276952433ce72e Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Fri, 19 Jul 2024 14:02:45 +0200 Subject: [PATCH 25/27] format --- fuzzers/libafl-fuzz/src/scheduler.rs | 13 ++-- fuzzers/libafl-fuzz/test/test-cmplog.c | 7 -- fuzzers/libafl-fuzz/test/test-instr.c | 14 ---- libafl/src/inputs/mod.rs | 3 +- libafl_bolts/src/rands/mod.rs | 11 +--- libafl_bolts/src/subrange.rs | 15 +++-- libafl_qemu/src/modules/calls.rs | 21 ++---- libafl_qemu/src/modules/usermode/asan.rs | 20 ++---- .../src/modules/usermode/asan_guest.rs | 4 +- libafl_qemu/src/modules/usermode/drcov.rs | 6 +- .../src/modules/usermode/injections.rs | 4 +- libafl_qemu/src/modules/usermode/snapshot.rs | 64 +++++-------------- 12 files changed, 53 insertions(+), 129 deletions(-) diff --git a/fuzzers/libafl-fuzz/src/scheduler.rs b/fuzzers/libafl-fuzz/src/scheduler.rs index 0b5477abb1..674241b441 100644 --- a/fuzzers/libafl-fuzz/src/scheduler.rs +++ b/fuzzers/libafl-fuzz/src/scheduler.rs @@ -4,7 +4,9 @@ use libafl::{ corpus::{CorpusId, HasTestcase, Testcase}, inputs::UsesInput, observers::{CanTrack, ObserversTuple}, - schedulers::{HasQueueCycles, MinimizerScheduler, RemovableScheduler, Scheduler, TestcaseScore}, + schedulers::{ + HasQueueCycles, MinimizerScheduler, RemovableScheduler, Scheduler, TestcaseScore, + }, state::{HasCorpus, HasRand, State, UsesState}, Error, HasMetadata, }; @@ -12,7 +14,10 @@ use libafl_bolts::{serdeany::SerdeAny, AsIter, HasRefCnt}; pub enum SupportedSchedulers { Queue(Q, PhantomData<(S, Q, CS, F, M, O)>), - Weighted(MinimizerScheduler, PhantomData<(S, Q, CS, F, M, O)>), + Weighted( + MinimizerScheduler, + PhantomData<(S, Q, CS, F, M, O)>, + ), } impl UsesState for SupportedSchedulers @@ -63,7 +68,7 @@ where CS: Scheduler, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, O: CanTrack, - F: TestcaseScore + F: TestcaseScore, { fn on_add(&mut self, state: &mut Self::State, id: CorpusId) -> Result<(), Error> { match self { @@ -113,7 +118,7 @@ where CS: Scheduler + HasQueueCycles, O: CanTrack, M: for<'a> AsIter<'a, Item = usize> + SerdeAny + HasRefCnt, - F: TestcaseScore + F: TestcaseScore, { fn queue_cycles(&self) -> u64 { match self { diff --git a/fuzzers/libafl-fuzz/test/test-cmplog.c b/fuzzers/libafl-fuzz/test/test-cmplog.c index 0c91b21c45..60e981a44c 100644 --- a/fuzzers/libafl-fuzz/test/test-cmplog.c +++ b/fuzzers/libafl-fuzz/test/test-cmplog.c @@ -7,32 +7,25 @@ #include int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t i) { - if (i < 15) return -1; if (buf[0] != 'A') return 0; int *icmp = (int *)(buf + 1); if (*icmp != 0x69694141) return 0; if (memcmp(buf + 5, "1234EF", 6) == 0) abort(); return 0; - } #ifdef __AFL_COMPILER int main(int argc, char *argv[]) { - unsigned char buf[1024]; ssize_t i; while (__AFL_LOOP(1000)) { - i = read(0, (char *)buf, sizeof(buf) - 1); if (i > 0) buf[i] = 0; LLVMFuzzerTestOneInput(buf, i); - } return 0; - } #endif - diff --git a/fuzzers/libafl-fuzz/test/test-instr.c b/fuzzers/libafl-fuzz/test/test-instr.c index 285528932c..a71baf4c19 100644 --- a/fuzzers/libafl-fuzz/test/test-instr.c +++ b/fuzzers/libafl-fuzz/test/test-instr.c @@ -23,38 +23,28 @@ #endif int main(int argc, char **argv) { - int fd = 0, cnt; char buff[8]; char *buf = buff; // we support command line parameter and stdin if (argc == 2) { - buf = argv[1]; } else { - if (argc >= 3 && strcmp(argv[1], "-f") == 0) { - if ((fd = open(argv[2], O_RDONLY)) < 0) { - fprintf(stderr, "Error: unable to open %s\n", argv[2]); exit(-1); - } - } if ((cnt = read(fd, buf, sizeof(buf) - 1)) < 1) { - printf("Hum?\n"); return 1; - } buf[cnt] = 0; - } if (getenv("AFL_DEBUG")) fprintf(stderr, "test-instr: %s\n", buf); @@ -62,7 +52,6 @@ int main(int argc, char **argv) { // we support three input cases (plus a 4th if stdin is used but there is no // input) switch (buf[0]) { - case '0': printf("Looks like a zero to me!\n"); break; @@ -74,10 +63,7 @@ int main(int argc, char **argv) { default: printf("Neither one or zero? How quaint!\n"); break; - } return 0; - } - diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 25ee62396e..2ba49dc112 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -36,7 +36,7 @@ use std::{fs::File, hash::Hash, io::Read, path::Path}; use libafl_bolts::fs::write_file_atomic; use libafl_bolts::{ ownedref::{OwnedMutSlice, OwnedSlice}, - subrange::{SubRangeSlice, SubRangeMutSlice}, + subrange::{SubRangeMutSlice, SubRangeSlice}, Error, HasLen, }; #[cfg(feature = "nautilus")] @@ -321,4 +321,3 @@ where (self.convert_cb)(input) } } - diff --git a/libafl_bolts/src/rands/mod.rs b/libafl_bolts/src/rands/mod.rs index 29140581fd..cbb015d139 100644 --- a/libafl_bolts/src/rands/mod.rs +++ b/libafl_bolts/src/rands/mod.rs @@ -1,15 +1,10 @@ //! The random number generators of `LibAFL` -use core::{ - debug_assert, - fmt::Debug, - sync::atomic::AtomicUsize, -}; - -use serde::{de::DeserializeOwned, Deserialize, Serialize}; - #[cfg(target_has_atomic = "ptr")] use core::sync::atomic::Ordering; +use core::{debug_assert, fmt::Debug, sync::atomic::AtomicUsize}; + +use serde::{de::DeserializeOwned, Deserialize, Serialize}; #[cfg(feature = "alloc")] pub mod loaded_dice; diff --git a/libafl_bolts/src/subrange.rs b/libafl_bolts/src/subrange.rs index c470a153c2..cb994e025b 100644 --- a/libafl_bolts/src/subrange.rs +++ b/libafl_bolts/src/subrange.rs @@ -1,10 +1,15 @@ //! Subrange of things. //! Convenient wrappers to handle sub-slices efficiently. -use core::cmp::min; -use core::ops::{Range, RangeBounds, Bound}; -use crate::HasLen; -use crate::ownedref::{OwnedMutSlice, OwnedSlice}; +use core::{ + cmp::min, + ops::{Bound, Range, RangeBounds}, +}; + +use crate::{ + ownedref::{OwnedMutSlice, OwnedSlice}, + HasLen, +}; /// An immutable contiguous subslice of a byte slice. /// It is mostly useful to cheaply wrap a subslice of a given input. @@ -105,8 +110,6 @@ impl<'a, T> HasLen for SubRangeMutSlice<'a, T> { } } - - /// Gets the relevant concrete start index from [`RangeBounds`] (inclusive) pub fn start_index(range: &R) -> usize where diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index a412abcbed..f870af154c 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -265,10 +265,7 @@ where .as_mut() .unwrap() .on_ret_all(emulator_modules, state, pc, ret_addr); - emulator_modules - .get_mut::() - .unwrap() - .collectors = collectors; + emulator_modules.get_mut::().unwrap().collectors = collectors; } fn gen_blocks_calls( @@ -360,12 +357,11 @@ where let call_cb = Box::new( move |emulator_modules: &mut EmulatorModules, state: Option<&mut S>, pc| { // eprintln!("CALL @ 0x{:#x}", pc + call_len); - let mut collectors = - if let Some(h) = emulator_modules.get_mut::() { - h.collectors.take() - } else { - return; - }; + let mut collectors = if let Some(h) = emulator_modules.get_mut::() { + h.collectors.take() + } else { + return; + }; if collectors.is_none() { return; // TODO fix this, it can be None on races ret } @@ -373,10 +369,7 @@ where .as_mut() .unwrap() .on_call_all(emulator_modules, state, pc, call_len); - emulator_modules - .get_mut::() - .unwrap() - .collectors = collectors; + emulator_modules.get_mut::().unwrap().collectors = collectors; }, ); emulator_modules.instruction_closure(call_addr, call_cb, false); diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index b48854a380..0917b52ad4 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -1204,9 +1204,7 @@ pub fn trace_write1_asan_snapshot( let h = emulator_modules.get_mut::().unwrap(); h.write_1(qemu, id as GuestAddr, addr); } - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, 1); } @@ -1224,9 +1222,7 @@ pub fn trace_write2_asan_snapshot( let h = emulator_modules.get_mut::().unwrap(); h.write_2(qemu, id as GuestAddr, addr); } - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, 2); } @@ -1244,9 +1240,7 @@ pub fn trace_write4_asan_snapshot( let h = emulator_modules.get_mut::().unwrap(); h.write_4(qemu, id as GuestAddr, addr); } - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, 4); } @@ -1264,9 +1258,7 @@ pub fn trace_write8_asan_snapshot( let h = emulator_modules.get_mut::().unwrap(); h.write_8(qemu, id as GuestAddr, addr); } - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, 8); } @@ -1285,9 +1277,7 @@ pub fn trace_write_n_asan_snapshot( let h = emulator_modules.get_mut::().unwrap(); h.read_n(qemu, id as GuestAddr, addr, size); } - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, size); } diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index 65c314a6ed..cadb1a9bc9 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -218,9 +218,7 @@ where S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); if !h.must_instrument(pc) { return None; } diff --git a/libafl_qemu/src/modules/usermode/drcov.rs b/libafl_qemu/src/modules/usermode/drcov.rs index ad0e4a71bc..f57adb6bec 100644 --- a/libafl_qemu/src/modules/usermode/drcov.rs +++ b/libafl_qemu/src/modules/usermode/drcov.rs @@ -286,11 +286,7 @@ pub fn exec_trace_block( ET: EmulatorModuleTuple, S: Unpin + UsesInput + HasMetadata, { - if emulator_modules - .get::() - .unwrap() - .full_trace - { + if emulator_modules.get::().unwrap().full_trace { DRCOV_IDS.lock().unwrap().as_mut().unwrap().push(id); } } diff --git a/libafl_qemu/src/modules/usermode/injections.rs b/libafl_qemu/src/modules/usermode/injections.rs index fcbda512fe..67e4ac253e 100644 --- a/libafl_qemu/src/modules/usermode/injections.rs +++ b/libafl_qemu/src/modules/usermode/injections.rs @@ -353,9 +353,7 @@ where log::trace!("syscall_hook {syscall} {SYS_execve}"); debug_assert!(i32::try_from(SYS_execve).is_ok()); if syscall == SYS_execve as i32 { - let _module = emulator_modules - .get_mut::() - .unwrap(); + let _module = emulator_modules.get_mut::().unwrap(); if x0 > 0 && x1 > 0 { let c_array = x1 as *const *const c_char; let cmd = unsafe { diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index 66f3dc6b46..7424766829 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -710,9 +710,7 @@ pub fn trace_write_snapshot( S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, SIZE); } @@ -726,9 +724,7 @@ pub fn trace_write_n_snapshot( S: Unpin + UsesInput, ET: EmulatorModuleTuple, { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(addr, size); } @@ -752,9 +748,7 @@ where ET: EmulatorModuleTuple, { if i64::from(sys_num) == SYS_munmap { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); if !h.is_unmap_allowed(a0 as GuestAddr, a1 as usize) { return SyscallHookResult::new(Some(0)); } @@ -785,21 +779,15 @@ where // NOT A COMPLETE LIST OF MEMORY EFFECTS match i64::from(sys_num) { SYS_read | SYS_pread64 => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a1, a2 as usize); } SYS_readlinkat => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a2, a3 as usize); } SYS_futex => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a0, a3 as usize); } #[cfg(not(any( @@ -810,37 +798,27 @@ where )))] SYS_newfstatat => { if a2 != 0 { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a2, 4096); // stat is not greater than a page } } #[cfg(any(cpu_target = "arm", cpu_target = "mips", cpu_target = "i386"))] SYS_fstatat64 => { if a2 != 0 { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a2, 4096); // stat is not greater than a page } } SYS_statfs | SYS_fstatfs | SYS_fstat => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a1, 4096); // stat is not greater than a page } SYS_getrandom => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.access(a0, a1 as usize); } SYS_brk => { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); if h.brk != result && result != 0 { /* brk has changed. we change mapping from the snapshotted brk address to the new target_brk * If no brk mapping has been made until now, change_mapped won't change anything and just create a new mapping. @@ -862,9 +840,7 @@ where #[cfg(any(cpu_target = "arm", cpu_target = "mips"))] if sys_const == SYS_mmap2 { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.add_mapped(result, a1 as usize, Some(prot)); } } @@ -872,31 +848,23 @@ where #[cfg(not(cpu_target = "arm"))] if sys_const == SYS_mmap { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.add_mapped(result, a1 as usize, Some(prot)); } } if sys_const == SYS_mremap { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); // TODO get the old permissions from the removed mapping h.remove_mapped(a0, a1 as usize); h.add_mapped(result, a2 as usize, None); } else if sys_const == SYS_mprotect { if let Ok(prot) = MmapPerms::try_from(a2 as i32) { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); h.change_mapped(a0, a1 as usize, Some(prot)); } } else if sys_const == SYS_munmap { - let h = emulator_modules - .get_mut::() - .unwrap(); + let h = emulator_modules.get_mut::().unwrap(); if !h.accurate_unmap && !h.is_unmap_allowed(a0, a1 as usize) { h.remove_mapped(a0, a1 as usize); } From 9092044b6eec5a122ff0c5520a2eec264dfa57d9 Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Fri, 19 Jul 2024 14:05:48 +0200 Subject: [PATCH 26/27] alloc --- libafl_bolts/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libafl_bolts/src/lib.rs b/libafl_bolts/src/lib.rs index 39eff0b6ad..b11e5870dc 100644 --- a/libafl_bolts/src/lib.rs +++ b/libafl_bolts/src/lib.rs @@ -131,6 +131,7 @@ pub mod serdeany; pub mod shmem; #[cfg(feature = "std")] pub mod staterestore; +#[cfg(feature = "alloc")] pub mod subrange; // TODO: reenable once ahash works in no-alloc #[cfg(any(feature = "xxh3", feature = "alloc"))] From fb9b17eeada029379131a9821d07d2e0cda8810a Mon Sep 17 00:00:00 2001 From: Romain Malmain Date: Fri, 19 Jul 2024 14:14:33 +0200 Subject: [PATCH 27/27] fix doc --- libafl/src/inputs/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index 2ba49dc112..75bba866bc 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -170,7 +170,7 @@ pub trait HasMutatorBytes: HasLen { where R: RangeBounds; - /// Creates a [`BytesSlice`] from this input, that can be used to slice a byte array. + /// Creates a [`SubRangeSlice`] from this input, that can be used to slice a byte array. fn sub_bytes(&self, range: R) -> SubRangeSlice where R: RangeBounds, @@ -178,7 +178,7 @@ pub trait HasMutatorBytes: HasLen { SubRangeSlice::new(OwnedSlice::from(self.bytes()), range) } - /// Creates a [`BytesSliceMut`] from this input, that can be used to slice a byte array. + /// Creates a [`SubRangeMutSlice`] from this input, that can be used to slice a byte array. fn sub_bytes_mut(&mut self, range: R) -> SubRangeMutSlice where R: RangeBounds, @@ -186,7 +186,7 @@ pub trait HasMutatorBytes: HasLen { SubRangeMutSlice::new(OwnedMutSlice::from(self.bytes_mut()), range) } - /// Creates a [`BytesSlice`] from this input, that can be used for local mutations. + /// Creates a [`BytesSubInput`] from this input, that can be used for local mutations. fn sub_input(&mut self, range: R) -> BytesSubInput where R: RangeBounds,