Add AsSlice, AsMutSlice traits, refactor MapObservers to be iterable, and have associated types (#477)

* from warning

* fix latest clippy

* clippy fixes++

* renamed shmem parameters

* renamed map to shmem

* make forkserver executor work for any (non-system) shmem

* Mem -> ShMem

* rework windows

* fix nit

* fix symbolic

* refacctor map observers

* iterator for map observers

* removed unused ownedptr, added asslice trait to most functions

* make map entry type an associated type

* fix fuzzers

* fix docs

* typo fix

* fix windows, add try_from_slice to shmid

* missing import

* fix fuzzbench

* cleanup

* fmt

* more asslice

* fmt

* added doc link about token-level fuzzing

* cods
This commit is contained in:
Dominik Maier 2022-01-19 00:02:33 +01:00 committed by GitHub
parent b67a7f5b60
commit 77e5965e97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 580 additions and 358 deletions

View File

@ -77,7 +77,10 @@ To start, we create the closure that we want to fuzz. It takes a buffer as input
```rust
extern crate libafl;
use libafl::inputs::{BytesInput, HasTargetBytes};
use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes},
};
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
@ -218,6 +221,7 @@ As we don't rely on any instrumentation engine, we have to manually track the sa
```rust
extern crate libafl;
use libafl::{
bolts::AsSlice,
inputs::{BytesInput, HasTargetBytes},
executors::ExitKind,
};

View File

@ -4,7 +4,7 @@ use std::path::PathBuf;
use std::ptr::write_volatile;
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -5,7 +5,7 @@
#![cfg_attr(not(any(windows, unix)), feature(default_alloc_error_handler))]
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, QueueCorpusScheduler},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -5,6 +5,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsMutSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -20,6 +20,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
ondisk::OnDiskMetadataFormat, CachedOnDiskCorpus, Corpus,

View File

@ -24,6 +24,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler,

View File

@ -21,6 +21,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler,

View File

@ -16,6 +16,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -19,6 +19,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -11,6 +11,7 @@ use libafl::{
current_nanos,
rands::StdRand,
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig},

View File

@ -12,6 +12,7 @@ use libafl::{
current_nanos,
rands::StdRand,
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -18,6 +18,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -18,6 +18,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -7,7 +7,7 @@ static GLOBAL: MiMalloc = MiMalloc;
use std::{env, path::PathBuf};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -7,7 +7,7 @@ static GLOBAL: MiMalloc = MiMalloc;
use std::{env, path::PathBuf};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
QueueCorpusScheduler,

View File

@ -4,7 +4,7 @@ use std::{
env,
io::{stdout, Write},
path::{Path, PathBuf},
process::{exit, Command},
process::exit,
};
use which::which;

View File

@ -13,6 +13,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Named},
AsMutSlice, AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -3,7 +3,7 @@
use klo_routines::*;
use libafl::inputs::{BytesInput, HasTargetBytes};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},

View File

@ -8,7 +8,7 @@ use core::cell::{Cell, RefCell};
use std::{path::PathBuf, rc::Rc};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{
Corpus, CorpusScheduler, InMemoryCorpus, OnDiskCorpus, QueueCorpusScheduler, Testcase,
},

View File

@ -11,6 +11,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsSlice,
},
corpus::{
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -7,7 +7,7 @@ use core::time::Duration;
use std::{env, path::PathBuf};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list},
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, PowerQueueCorpusScheduler},
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},

View File

@ -542,7 +542,7 @@ impl LlmpMsg {
/// Gets the buffer from this message as slice, with the corrent length.
#[inline]
pub fn as_slice<SHM: ShMem>(&self, map: &mut LlmpSharedMap<SHM>) -> Result<&[u8], Error> {
pub fn try_as_slice<SHM: ShMem>(&self, map: &mut LlmpSharedMap<SHM>) -> Result<&[u8], Error> {
unsafe {
if self.in_shmem(map) {
Ok(self.as_slice_unsafe())
@ -1110,7 +1110,7 @@ where
#[allow(clippy::cast_ptr_alignment)]
let mut end_of_page_msg = (*out).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
(*end_of_page_msg).map_size = new_map_shmem.shmem.len();
(*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_slice();
(*end_of_page_msg).shm_str = *new_map_shmem.shmem.id().as_array();
/* Send the last msg on the old buf */
self.send(out, true)?;
@ -1439,7 +1439,7 @@ where
// Map the new page. The old one should be unmapped by Drop
self.current_recv_shmem =
LlmpSharedMap::existing(self.shmem_provider.shmem_from_id_and_size(
ShMemId::from_slice(&pageinfo_cpy.shm_str),
ShMemId::from_array(&pageinfo_cpy.shm_str),
pageinfo_cpy.map_size,
)?);
page = self.current_recv_shmem.page_mut();
@ -1512,7 +1512,7 @@ where
(*msg).sender,
(*msg).tag,
(*msg).flags,
(*msg).as_slice(&mut self.current_recv_shmem)?,
(*msg).try_as_slice(&mut self.current_recv_shmem)?,
)),
None => None,
})
@ -1527,7 +1527,7 @@ where
Ok((
(*msg).sender,
(*msg).tag,
(*msg).as_slice(&mut self.current_recv_shmem)?,
(*msg).try_as_slice(&mut self.current_recv_shmem)?,
))
}
}
@ -1997,7 +1997,7 @@ where
(*msg).tag = LLMP_TAG_NEW_SHM_CLIENT;
#[allow(clippy::cast_ptr_alignment)]
let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
(*pageinfo).shm_str = *shmem_description.id.as_slice();
(*pageinfo).shm_str = *shmem_description.id.as_array();
(*pageinfo).map_size = shmem_description.size;
sender.send(msg, true)
}
@ -2329,7 +2329,7 @@ where
let pageinfo = (*msg).buf.as_mut_ptr() as *mut LlmpPayloadSharedMapInfo;
match self.shmem_provider.shmem_from_id_and_size(
ShMemId::from_slice(&(*pageinfo).shm_str),
ShMemId::from_array(&(*pageinfo).shm_str),
(*pageinfo).map_size,
) {
Ok(new_shmem) => {
@ -2363,7 +2363,7 @@ where
let mut should_forward_msg = true;
let map = &mut self.llmp_clients[client_id as usize].current_recv_shmem;
let msg_buf = (*msg).as_slice(map)?;
let msg_buf = (*msg).try_as_slice(map)?;
if let LlmpMsgHookResult::Handled =
(on_new_msg)(client_id, (*msg).tag, (*msg).flags, msg_buf)?
{

View File

@ -30,6 +30,12 @@ pub trait AsSlice<T> {
fn as_slice(&self) -> &[T];
}
/// Can be converted to a mutable slice
pub trait AsMutSlice<T> {
/// Convert to a slice
fn as_mut_slice(&mut self) -> &mut [T];
}
/// Has a length field
pub trait HasLen {
/// The length

View File

@ -6,7 +6,10 @@ and forwards them over unix domain sockets.
*/
use crate::{
bolts::shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider},
bolts::{
shmem::{ShMem, ShMemDescription, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error,
};
use core::{mem::ManuallyDrop, ptr::addr_of};
@ -88,11 +91,20 @@ where
fn len(&self) -> usize {
self.inner.len()
}
}
impl<SH> AsSlice<u8> for ServedShMem<SH>
where
SH: ShMem,
{
fn as_slice(&self) -> &[u8] {
self.inner.as_slice()
}
}
impl<SH> AsMutSlice<u8> for ServedShMem<SH>
where
SH: ShMem,
{
fn as_mut_slice(&mut self) -> &mut [u8] {
self.inner.as_mut_slice()
}
@ -124,7 +136,7 @@ where
.recv_fds(&mut shm_slice, &mut fd_buf)
.expect("Did not receive a response");
let server_id = ShMemId::from_slice(&shm_slice);
let server_id = ShMemId::from_array(&shm_slice);
let server_fd: i32 = server_id.into();
Ok((server_fd, fd_buf[0]))
}

View File

@ -1,7 +1,12 @@
//! Wrappers that abstracts references (or pointers) and owned data accesses.
// The serialization is towards owned, allowing to serialize pointers without troubles.
use alloc::{boxed::Box, vec::Vec};
use crate::bolts::{AsMutSlice, AsSlice};
use alloc::{
boxed::Box,
slice::{Iter, IterMut},
vec::Vec,
};
use core::{clone::Clone, fmt::Debug, slice};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -234,6 +239,15 @@ impl<'a, T> OwnedSlice<'a, T> {
}
}
impl<'a, 'it, T> IntoIterator for &'it OwnedSlice<'a, T> {
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
/// Create a new [`OwnedSlice`] from a vector
impl<'a, T> From<Vec<T>> for OwnedSlice<'a, T> {
fn from(vec: Vec<T>) -> Self {
@ -274,10 +288,10 @@ impl<'a, T> From<OwnedSliceMut<'a, T>> for OwnedSlice<'a, T> {
}
}
impl<'a, T: Sized> OwnedSlice<'a, T> {
impl<'a, T: Sized> AsSlice<T> for OwnedSlice<'a, T> {
/// Get the [`OwnedSlice`] as slice.
#[must_use]
pub fn as_slice(&self) -> &[T] {
fn as_slice(&self) -> &[T] {
match &self.inner {
OwnedSliceInner::Ref(r) => r,
OwnedSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) },
@ -361,6 +375,24 @@ pub struct OwnedSliceMut<'a, T: 'a + Sized> {
inner: OwnedSliceMutInner<'a, T>,
}
impl<'a, 'it, T> IntoIterator for &'it mut OwnedSliceMut<'a, T> {
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<'a, 'it, T> IntoIterator for &'it OwnedSliceMut<'a, T> {
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, T: 'a + Sized> OwnedSliceMut<'a, T> {
/// Create a new [`OwnedSliceMut`] from a raw pointer and length
///
@ -382,20 +414,21 @@ impl<'a, T: 'a + Sized> OwnedSliceMut<'a, T> {
}
}
impl<'a, T: Sized> OwnedSliceMut<'a, T> {
impl<'a, T: Sized> AsSlice<T> for OwnedSliceMut<'a, T> {
/// Get the value as slice
#[must_use]
pub fn as_slice(&self) -> &[T] {
fn as_slice(&self) -> &[T] {
match &self.inner {
OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) },
OwnedSliceMutInner::Ref(r) => r,
OwnedSliceMutInner::Owned(v) => v.as_slice(),
}
}
}
impl<'a, T: Sized> AsMutSlice<T> for OwnedSliceMut<'a, T> {
/// Get the value as mut slice
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
fn as_mut_slice(&mut self) -> &mut [T] {
match &mut self.inner {
OwnedSliceMutInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts_mut(*rr, *len) },
OwnedSliceMutInner::Ref(r) => r,
@ -608,140 +641,3 @@ where
}
}
}
/// Wrap a C-style pointer to an array (with size) and convert to a Vec on serialize
#[derive(Clone, Debug)]
pub enum OwnedArrayPtr<T: Sized> {
/// Ptr to a slice
ArrayPtr((*const T, usize)),
/// A owned [`Vec`].
Owned(Vec<T>),
}
impl<T: Sized + Serialize> Serialize for OwnedArrayPtr<T> {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_slice().serialize(se)
}
}
impl<'de, T: Sized + Serialize> Deserialize<'de> for OwnedArrayPtr<T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(de).map(OwnedArrayPtr::Owned)
}
}
impl<T: Sized> OwnedArrayPtr<T> {
/// Get a slice from this array.
#[must_use]
pub fn as_slice(&self) -> &[T] {
match self {
OwnedArrayPtr::ArrayPtr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
OwnedArrayPtr::Owned(v) => v.as_slice(),
}
}
}
impl<T> IntoOwned for OwnedArrayPtr<T>
where
T: Sized + Clone,
{
#[must_use]
fn is_owned(&self) -> bool {
match self {
OwnedArrayPtr::ArrayPtr(_) => false,
OwnedArrayPtr::Owned(_) => true,
}
}
#[must_use]
fn into_owned(self) -> Self {
match self {
OwnedArrayPtr::ArrayPtr(p) => unsafe {
OwnedArrayPtr::Owned(core::slice::from_raw_parts(p.0, p.1).to_vec())
},
OwnedArrayPtr::Owned(v) => OwnedArrayPtr::Owned(v),
}
}
}
/// Wrap a C-style mutable pointer to an array (with size) and convert to a Vec on serialize
#[derive(Clone, Debug)]
pub enum OwnedArrayPtrMut<T: Sized> {
/// A ptr to the array (or slice).
ArrayPtr((*mut T, usize)),
/// An owned [`Vec`].
Owned(Vec<T>),
}
impl<T: Sized + Serialize> Serialize for OwnedArrayPtrMut<T> {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.as_slice().serialize(se)
}
}
impl<'de, T: Sized + Serialize> Deserialize<'de> for OwnedArrayPtrMut<T>
where
Vec<T>: Deserialize<'de>,
{
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Deserialize::deserialize(de).map(OwnedArrayPtrMut::Owned)
}
}
impl<T: Sized> OwnedArrayPtrMut<T> {
/// Return this array as slice
#[must_use]
pub fn as_slice(&self) -> &[T] {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) },
OwnedArrayPtrMut::Owned(v) => v.as_slice(),
}
}
/// Return this array as mut slice
#[must_use]
pub fn as_mut_slice(&mut self) -> &mut [T] {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe { core::slice::from_raw_parts_mut(p.0, p.1) },
OwnedArrayPtrMut::Owned(v) => v.as_mut_slice(),
}
}
}
impl<T> IntoOwned for OwnedArrayPtrMut<T>
where
T: Sized + Clone,
{
#[must_use]
fn is_owned(&self) -> bool {
match self {
OwnedArrayPtrMut::ArrayPtr(_) => false,
OwnedArrayPtrMut::Owned(_) => true,
}
}
#[must_use]
fn into_owned(self) -> Self {
match self {
OwnedArrayPtrMut::ArrayPtr(p) => unsafe {
OwnedArrayPtrMut::Owned(core::slice::from_raw_parts(p.0, p.1).to_vec())
},
OwnedArrayPtrMut::Owned(v) => OwnedArrayPtrMut::Owned(v),
}
}
}

View File

@ -3,7 +3,10 @@
#[cfg(all(unix, feature = "std"))]
use crate::bolts::os::pipes::Pipe;
use crate::Error;
use crate::{
bolts::{AsMutSlice, AsSlice},
Error,
};
use alloc::{rc::Rc, string::ToString};
use core::{
cell::RefCell,
@ -89,10 +92,17 @@ pub struct ShMemId {
}
impl ShMemId {
/// Create a new id from a fixed-size string
/// Create a new id from a fixed-size string/bytes array
/// It should contain a valid cstring.
#[must_use]
pub fn from_slice(slice: &[u8; 20]) -> Self {
Self { id: *slice }
pub fn from_array(array: &[u8; 20]) -> Self {
Self { id: *array }
}
/// Try to create a new id from a bytes string.
/// The slice must have a length of at least 20 bytes and contain a valid cstring.
pub fn try_from_slice(slice: &[u8]) -> Result<Self, Error> {
Ok(Self::from_array(&slice[0..20].try_into()?))
}
/// Create a new id from an int
@ -113,7 +123,7 @@ impl ShMemId {
/// Get the id as a fixed-length slice
#[must_use]
pub fn as_slice(&self) -> &[u8; 20] {
pub fn as_array(&self) -> &[u8; 20] {
&self.id
}
@ -129,6 +139,11 @@ impl ShMemId {
alloc::str::from_utf8(&self.id[..self.null_pos()]).unwrap()
}
}
impl AsSlice<u8> for ShMemId {
fn as_slice(&self) -> &[u8] {
&self.id
}
}
impl From<ShMemId> for i32 {
fn from(id: ShMemId) -> i32 {
@ -145,7 +160,7 @@ impl Display for ShMemId {
/// A [`ShMem`] is an interface to shared maps.
/// They are the backbone of [`crate::bolts::llmp`] for inter-process communication.
/// All you need for scaling on a new target is to implement this interface, as well as the respective [`ShMemProvider`].
pub trait ShMem: Sized + Debug + Clone {
pub trait ShMem: Sized + Debug + Clone + AsSlice<u8> + AsMutSlice<u8> {
/// Get the id of this shared memory mapping
fn id(&self) -> ShMemId;
@ -165,12 +180,6 @@ pub trait ShMem: Sized + Debug + Clone {
}
}
/// The actual shared map, in memory
fn as_slice(&self) -> &[u8];
/// The actual shared map, mutable
fn as_mut_slice(&mut self) -> &mut [u8];
/// Write this map's config to env
#[cfg(feature = "std")]
fn write_to_env(&self, env_name: &str) -> Result<(), Error> {
@ -264,11 +273,21 @@ where
fn len(&self) -> usize {
self.internal.len()
}
}
impl<T> AsSlice<u8> for RcShMem<T>
where
T: ShMemProvider + Debug,
{
fn as_slice(&self) -> &[u8] {
self.internal.as_slice()
}
}
impl<T> AsMutSlice<u8> for RcShMem<T>
where
T: ShMemProvider + Debug,
{
fn as_mut_slice(&mut self) -> &mut [u8] {
self.internal.as_mut_slice()
}
@ -489,7 +508,10 @@ pub mod unix_shmem {
use std::{io::Write, process};
use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider},
bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error,
};
#[cfg(unix)]
@ -691,11 +713,15 @@ pub mod unix_shmem {
fn len(&self) -> usize {
self.map_size
}
}
impl AsSlice<u8> for MmapShMem {
fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) }
}
}
impl AsMutSlice<u8> for MmapShMem {
fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
}
@ -790,11 +816,15 @@ pub mod unix_shmem {
fn len(&self) -> usize {
self.map_size
}
}
impl AsSlice<u8> for CommonUnixShMem {
fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) }
}
}
impl AsMutSlice<u8> for CommonUnixShMem {
fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
}
@ -858,7 +888,10 @@ pub mod unix_shmem {
use std::ffi::CString;
use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider},
bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error,
};
@ -992,11 +1025,15 @@ pub mod unix_shmem {
fn len(&self) -> usize {
self.map_size
}
}
impl AsSlice<u8> for AshmemShMem {
fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) }
}
}
impl AsMutSlice<u8> for AshmemShMem {
fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
}
@ -1069,7 +1106,10 @@ pub mod unix_shmem {
pub mod win32_shmem {
use crate::{
bolts::shmem::{ShMem, ShMemId, ShMemProvider},
bolts::{
shmem::{ShMem, ShMemId, ShMemProvider},
AsMutSlice, AsSlice,
},
Error,
};
@ -1141,7 +1181,7 @@ pub mod win32_shmem {
}
Ok(Self {
id: ShMemId::from_slice(&map_str_bytes[0..20].try_into().unwrap()),
id: ShMemId::try_from_slice(&map_str_bytes).unwrap(),
handle,
map,
map_size,
@ -1189,11 +1229,14 @@ pub mod win32_shmem {
fn len(&self) -> usize {
self.map_size
}
}
impl AsSlice<u8> for Win32ShMem {
fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.map, self.map_size) }
}
}
impl AsMutSlice<u8> for Win32ShMem {
fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.map, self.map_size) }
}
@ -1348,7 +1391,10 @@ impl<T: ShMem> std::io::Seek for ShMemCursor<T> {
mod tests {
use serial_test::serial;
use crate::bolts::shmem::{ShMem, ShMemProvider, StdShMemProvider};
use crate::bolts::{
shmem::{ShMemProvider, StdShMemProvider},
AsMutSlice, AsSlice,
};
#[test]
#[serial]

View File

@ -12,7 +12,10 @@ use std::{
};
use crate::{
bolts::shmem::{ShMem, ShMemProvider},
bolts::{
shmem::{ShMem, ShMemProvider},
AsSlice,
},
Error,
};

View File

@ -105,7 +105,7 @@ where
/// # Example
/// ```
/// use std::{io::Write, process::{Stdio, Command, Child}};
/// use libafl::{Error, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}};
/// use libafl::{Error, bolts::AsSlice, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}};
/// #[derive(Debug)]
/// struct MyExecutor;
///

View File

@ -19,6 +19,7 @@ use crate::{
bolts::{
os::{dup2, pipes::Pipe},
shmem::{ShMem, ShMemProvider, StdShMemProvider},
AsMutSlice, AsSlice,
},
executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, Input},
@ -832,6 +833,7 @@ mod tests {
bolts::{
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsMutSlice,
},
executors::ForkserverExecutor,
inputs::NopInput,

View File

@ -32,6 +32,7 @@ pub mod command;
pub use command::CommandExecutor;
use crate::{
bolts::AsSlice,
inputs::{HasTargetBytes, Input},
observers::ObserversTuple,
Error,

View File

@ -11,7 +11,7 @@ use serde::{Deserialize, Serialize};
use crate::{
bolts::{
tuples::{MatchName, Named},
AsSlice, HasRefCnt,
AsMutSlice, AsSlice, HasRefCnt,
},
corpus::Testcase,
events::{Event, EventFirer},
@ -214,6 +214,12 @@ impl AsSlice<usize> for MapIndexesMetadata {
self.list.as_slice()
}
}
impl AsMutSlice<usize> for MapIndexesMetadata {
/// Convert to a slice
fn as_mut_slice(&mut self) -> &mut [usize] {
self.list.as_mut_slice()
}
}
impl HasRefCnt for MapIndexesMetadata {
fn refcnt(&self) -> isize {
@ -249,6 +255,13 @@ impl AsSlice<usize> for MapNoveltiesMetadata {
self.list.as_slice()
}
}
impl AsMutSlice<usize> for MapNoveltiesMetadata {
/// Convert to a slice
#[must_use]
fn as_mut_slice(&mut self) -> &mut [usize] {
self.list.as_mut_slice()
}
}
impl MapNoveltiesMetadata {
/// Creates a new [`struct@MapNoveltiesMetadata`]
#[must_use]
@ -308,7 +321,7 @@ where
/// Create new `MapFeedbackState` for the observer type.
pub fn with_observer<O>(map_observer: &O) -> Self
where
O: MapObserver<T>,
O: MapObserver<Entry = T>,
T: Debug,
{
Self {
@ -335,7 +348,7 @@ pub struct MapFeedback<I, N, O, R, S, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>,
O: MapObserver<T>,
O: MapObserver,
N: IsNovel<T>,
S: HasFeedbackStates,
{
@ -355,7 +368,7 @@ impl<I, N, O, R, S, T> Feedback<I, S> for MapFeedback<I, N, O, R, S, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>,
O: MapObserver<T>,
O: MapObserver<Entry = T>,
N: IsNovel<T>,
I: Input,
S: HasFeedbackStates + HasClientPerfMonitor + Debug,
@ -464,7 +477,7 @@ where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
R: Reducer<T>,
N: IsNovel<T>,
O: MapObserver<T>,
O: MapObserver,
S: HasFeedbackStates,
{
#[inline]
@ -485,7 +498,7 @@ where
+ Debug,
R: Reducer<T>,
N: IsNovel<T>,
O: MapObserver<T>,
O: MapObserver,
S: HasFeedbackStates,
{
/// Create new `MapFeedback`
@ -557,7 +570,7 @@ pub struct ReachabilityFeedback<O> {
impl<O> ReachabilityFeedback<O>
where
O: MapObserver<usize>,
O: MapObserver<Entry = usize>,
{
/// Creates a new [`ReachabilityFeedback`] for a [`MapObserver`].
#[must_use]
@ -583,7 +596,7 @@ where
impl<I, O, S> Feedback<I, S> for ReachabilityFeedback<O>
where
I: Input,
O: MapObserver<usize>,
O: MapObserver<Entry = usize>,
S: HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
@ -632,7 +645,7 @@ where
impl<O> Named for ReachabilityFeedback<O>
where
O: MapObserver<usize>,
O: MapObserver<Entry = usize>,
{
#[inline]
fn name(&self) -> &str {

View File

@ -1,5 +1,6 @@
//! The `EncodedInput` is the "normal" input, a map of codes, that can be sent directly to the client
//! (As opposed to other, more abstract, imputs, like an Grammar-Based AST Input)
//! See also [the paper on token-level fuzzing](https://www.usenix.org/system/files/sec21-salls.pdf)
use ahash::AHasher;
use core::hash::Hasher;

View File

@ -113,11 +113,11 @@ pub mod stats {
pub use crate::monitors::UserStats;
}
use alloc::string::String;
use core::fmt;
use alloc::string::{FromUtf8Error, String};
use core::{array::TryFromSliceError, fmt, num::ParseIntError, num::TryFromIntError};
#[cfg(feature = "std")]
use std::{env::VarError, io, num::ParseIntError, num::TryFromIntError, string::FromUtf8Error};
use std::{env::VarError, io};
/// Main error struct for AFL
#[derive(Debug)]
@ -209,10 +209,9 @@ impl From<io::Error> for Error {
}
}
#[cfg(feature = "std")]
impl From<FromUtf8Error> for Error {
fn from(err: FromUtf8Error) -> Self {
Self::Unknown(format!("Could not convert byte to utf-8: {:?}", err))
Self::Unknown(format!("Could not convert byte / utf-8: {:?}", err))
}
}
@ -223,20 +222,24 @@ impl From<VarError> for Error {
}
}
#[cfg(feature = "std")]
impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self {
Self::Unknown(format!("Failed to parse Int: {:?}", err))
}
}
#[cfg(feature = "std")]
impl From<TryFromIntError> for Error {
fn from(err: TryFromIntError) -> Self {
Self::IllegalState(format!("Expected conversion failed: {:?}", err))
}
}
impl From<TryFromSliceError> for Error {
fn from(err: TryFromSliceError) -> Self {
Self::IllegalArgument(format!("Could not convert slice: {:?}", err))
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}

View File

@ -11,7 +11,7 @@ use crate::{
bolts::{
rands::Rand,
tuples::{tuple_list, tuple_list_type, NamedTuple},
AsSlice,
AsMutSlice, AsSlice,
},
corpus::Corpus,
inputs::Input,
@ -33,10 +33,17 @@ pub struct LogMutationMetadata {
crate::impl_serdeany!(LogMutationMetadata);
impl AsSlice<String> for LogMutationMetadata {
#[must_use]
fn as_slice(&self) -> &[String] {
self.list.as_slice()
}
}
impl AsMutSlice<String> for LogMutationMetadata {
#[must_use]
fn as_mut_slice(&mut self) -> &mut [String] {
self.list.as_mut_slice()
}
}
impl LogMutationMetadata {
/// Creates new [`struct@LogMutationMetadata`].

View File

@ -8,7 +8,7 @@ use core::fmt::Debug;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{
bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice},
bolts::{ownedref::OwnedRefMut, tuples::Named, AsMutSlice, AsSlice},
observers::Observer,
state::HasMetadata,
Error,
@ -69,6 +69,13 @@ impl AsSlice<CmpValues> for CmpValuesMetadata {
self.list.as_slice()
}
}
impl AsMutSlice<CmpValues> for CmpValuesMetadata {
/// Convert to a slice
#[must_use]
fn as_mut_slice(&mut self) -> &mut [CmpValues] {
self.list.as_mut_slice()
}
}
impl CmpValuesMetadata {
/// Creates a new [`struct@CmpValuesMetadata`]
@ -111,10 +118,10 @@ where
fn usable_count(&self) -> usize;
/// Get the `CmpMap`
fn map(&self) -> &CM;
fn cmp_map(&self) -> &CM;
/// Get the `CmpMap` (mut)
fn map_mut(&mut self) -> &mut CM;
fn cmp_map_mut(&mut self) -> &mut CM;
/// Add [`struct@CmpValuesMetadata`] to the State including the logged values.
/// This routine does a basic loop filtering because loop index cmps are not interesting.
@ -132,7 +139,7 @@ where
meta.list.clear();
let count = self.usable_count();
for i in 0..count {
let execs = self.map().usable_executions_for(i);
let execs = self.cmp_map().usable_executions_for(i);
if execs > 0 {
// Recongize loops and discard if needed
if execs > 4 {
@ -143,7 +150,7 @@ where
let mut last: Option<CmpValues> = None;
for j in 0..execs {
let val = self.map().values_of(i, j);
let val = self.cmp_map().values_of(i, j);
if let Some(l) = last.and_then(|x| x.to_u64_tuple()) {
if let Some(v) = val.to_u64_tuple() {
if l.0.wrapping_add(1) == v.0 {
@ -173,7 +180,7 @@ where
}
}
for j in 0..execs {
meta.list.push(self.map().values_of(i, j));
meta.list.push(self.cmp_map().values_of(i, j));
}
}
}
@ -187,7 +194,7 @@ pub struct StdCmpObserver<'a, CM>
where
CM: CmpMap + Serialize + DeserializeOwned,
{
map: OwnedRefMut<'a, CM>,
cmp_map: OwnedRefMut<'a, CM>,
size: Option<OwnedRefMut<'a, usize>>,
name: String,
}
@ -199,17 +206,17 @@ where
/// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize {
match &self.size {
None => self.map.as_ref().len(),
None => self.cmp_map.as_ref().len(),
Some(o) => *o.as_ref(),
}
}
fn map(&self) -> &CM {
self.map.as_ref()
fn cmp_map(&self) -> &CM {
self.cmp_map.as_ref()
}
fn map_mut(&mut self) -> &mut CM {
self.map.as_mut()
fn cmp_map_mut(&mut self) -> &mut CM {
self.cmp_map.as_mut()
}
}
@ -218,7 +225,7 @@ where
CM: CmpMap + Serialize + DeserializeOwned,
{
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
self.map.as_mut().reset()?;
self.cmp_map.as_mut().reset()?;
Ok(())
}
}
@ -242,7 +249,7 @@ where
Self {
name: name.to_string(),
size: None,
map: OwnedRefMut::Ref(map),
cmp_map: OwnedRefMut::Ref(map),
}
}
@ -252,7 +259,7 @@ where
Self {
name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)),
map: OwnedRefMut::Ref(map),
cmp_map: OwnedRefMut::Ref(map),
}
}
}

View File

@ -5,7 +5,12 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{fmt::Debug, hash::Hasher, slice::from_raw_parts};
use core::{
fmt::Debug,
hash::Hasher,
iter::Flatten,
slice::{from_raw_parts, Iter, IterMut},
};
use intervaltree::IntervalTree;
use num_traits::PrimInt;
use serde::{Deserialize, Serialize};
@ -14,41 +19,36 @@ use crate::{
bolts::{
ownedref::{OwnedRefMut, OwnedSliceMut},
tuples::Named,
HasLen,
AsMutSlice, AsSlice, HasLen,
},
observers::Observer,
Error,
};
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
pub trait MapObserver<T>: HasLen + Named + Serialize + serde::de::DeserializeOwned + Debug
where
T: PrimInt + Default + Copy + Debug,
{
/// Get the map if the observer can be represented with a slice
fn map(&self) -> Option<&[T]>;
/// Compute the hash of a slice
fn hash_slice<T: PrimInt>(slice: &[T]) -> u64 {
let mut hasher = AHasher::new_with_keys(0, 0);
let ptr = slice.as_ptr() as *const u8;
let map_size = slice.len() / core::mem::size_of::<T>();
unsafe {
hasher.write(from_raw_parts(ptr, map_size));
}
hasher.finish()
}
/// Get the map (mutable) if the observer can be represented with a slice
fn map_mut(&mut self) -> Option<&mut [T]>;
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned + Debug {
/// Type of each entry in this map
type Entry: PrimInt + Default + Copy + Debug;
/// Get the value at `idx`
fn get(&self, idx: usize) -> &T {
&self
.map()
.expect("Cannot get a map that cannot be represented as slice")[idx]
}
fn get(&self, idx: usize) -> &Self::Entry;
/// Get the value at `idx` (mutable)
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self
.map_mut()
.expect("Cannot get a map that cannot be represented as slice")[idx]
}
fn get_mut(&mut self, idx: usize) -> &mut Self::Entry;
/// Get the number of usable entries in the map (all by default)
fn usable_count(&self) -> usize {
self.len()
}
fn usable_count(&self) -> usize;
/// Count the set bytes in the map
fn count_bytes(&self) -> u64 {
@ -64,27 +64,16 @@ where
}
/// Compute the hash of the map
fn hash(&self) -> u64 {
let mut hasher = AHasher::new_with_keys(0, 0);
let slice = self
.map()
.expect("Cannot hash a map that cannot be represented as slice");
let ptr = slice.as_ptr() as *const u8;
let map_size = slice.len() / core::mem::size_of::<T>();
unsafe {
hasher.write(from_raw_parts(ptr, map_size));
}
hasher.finish()
}
fn hash(&self) -> u64;
/// Get the initial value for reset()
fn initial(&self) -> T;
fn initial(&self) -> Self::Entry;
/// Get the initial value for reset()
fn initial_mut(&mut self) -> &mut T;
fn initial_mut(&mut self) -> &mut Self::Entry;
/// Set the initial value for reset()
fn set_initial(&mut self, initial: T);
fn set_initial(&mut self, initial: Self::Entry);
/// Reset the map
#[inline]
@ -97,6 +86,16 @@ where
}
Ok(())
}
/// Get these observer's contents as [`Vec`]
fn to_vec(&self) -> Vec<Self::Entry> {
let cnt = self.usable_count();
let mut res = Vec::with_capacity(cnt);
for i in 0..cnt {
res.push(*self.get(i));
}
res
}
}
/// The Map Observer retrieves the state of a map,
@ -117,7 +116,7 @@ where
impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>,
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -145,18 +144,53 @@ where
}
}
impl<'a, T> MapObserver<T> for StdMapObserver<'a, T>
impl<'a, 'it, T> IntoIterator for &'it StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, 'it, T> IntoIterator for &'it mut StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<'a, T> MapObserver for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Entry = T;
#[inline]
fn map(&self) -> Option<&[T]> {
Some(self.map.as_slice())
fn get(&self, pos: usize) -> &T {
&self.as_slice()[pos]
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [T]> {
Some(self.map.as_mut_slice())
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
#[inline]
fn usable_count(&self) -> usize {
self.as_slice().len()
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
#[inline]
@ -173,6 +207,31 @@ where
fn set_initial(&mut self, initial: T) {
self.initial = initial;
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T> AsSlice<T> for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T> AsMutSlice<T> for StdMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[must_use]
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
}
impl<'a, T> StdMapObserver<'a, T>
@ -251,7 +310,7 @@ where
impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>,
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -279,24 +338,35 @@ where
}
}
impl<'a, T, const N: usize> MapObserver<T> for ConstMapObserver<'a, T, N>
impl<'a, 'it, T, const N: usize> IntoIterator for &'it ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn usable_count(&self) -> usize {
N
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
#[inline]
fn map(&self) -> Option<&[T]> {
Some(self.map.as_slice())
impl<'a, 'it, T, const N: usize> IntoIterator for &'it mut ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [T]> {
Some(self.map.as_mut_slice())
}
impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Entry = T;
#[inline]
fn initial(&self) -> T {
@ -312,6 +382,47 @@ where
fn set_initial(&mut self, initial: T) {
self.initial = initial;
}
#[inline]
fn get(&self, idx: usize) -> &T {
&self.as_slice()[idx]
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
fn usable_count(&self) -> usize {
self.as_slice().len()
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T, const N: usize> AsSlice<T> for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T, const N: usize> AsMutSlice<T> for ConstMapObserver<'a, T, N>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
}
impl<'a, T, const N: usize> ConstMapObserver<'a, T, N>
@ -373,7 +484,7 @@ where
impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>,
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -401,24 +512,35 @@ where
}
}
impl<'a, T> MapObserver<T> for VariableMapObserver<'a, T>
impl<'a, 'it, T> IntoIterator for &'it VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn map(&self) -> Option<&[T]> {
Some(self.map.as_slice())
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Iter<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [T]> {
Some(self.map.as_mut_slice())
impl<'a, 'it, T> IntoIterator for &'it mut VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = IterMut<'it, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
#[inline]
fn usable_count(&self) -> usize {
*self.size.as_ref()
}
impl<'a, T> MapObserver for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Entry = T;
#[inline]
fn initial(&self) -> T {
@ -434,6 +556,45 @@ where
fn set_initial(&mut self, initial: T) {
self.initial = initial;
}
#[inline]
fn usable_count(&self) -> usize {
*self.size.as_ref()
}
fn get(&self, idx: usize) -> &T {
&self.as_slice()[idx]
}
fn get_mut(&mut self, idx: usize) -> &mut T {
&mut self.as_mut_slice()[idx]
}
fn hash(&self) -> u64 {
hash_slice(self.as_slice())
}
fn to_vec(&self) -> Vec<T> {
self.as_slice().to_vec()
}
}
impl<'a, T> AsSlice<T> for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_slice(&self) -> &[T] {
self.map.as_slice()
}
}
impl<'a, T> AsMutSlice<T> for VariableMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [T] {
self.map.as_mut_slice()
}
}
impl<'a, T> VariableMapObserver<'a, T>
@ -498,7 +659,7 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [
impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M>
where
M: MapObserver<u8> + Observer<I, S>,
M: MapObserver<Entry = u8> + Observer<I, S>,
{
#[inline]
fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
@ -527,7 +688,7 @@ where
impl<M> HasLen for HitcountsMapObserver<M>
where
M: MapObserver<u8>,
M: MapObserver,
{
#[inline]
fn len(&self) -> usize {
@ -535,24 +696,11 @@ where
}
}
impl<M> MapObserver<u8> for HitcountsMapObserver<M>
impl<M> MapObserver for HitcountsMapObserver<M>
where
M: MapObserver<u8>,
M: MapObserver<Entry = u8>,
{
#[inline]
fn map(&self) -> Option<&[u8]> {
self.base.map()
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [u8]> {
self.base.map_mut()
}
#[inline]
fn usable_count(&self) -> usize {
self.base.usable_count()
}
type Entry = u8;
#[inline]
fn initial(&self) -> u8 {
@ -568,6 +716,47 @@ where
fn set_initial(&mut self, initial: u8) {
self.base.set_initial(initial);
}
#[inline]
fn usable_count(&self) -> usize {
self.base.usable_count()
}
#[inline]
fn get(&self, idx: usize) -> &u8 {
self.base.get(idx)
}
#[inline]
fn get_mut(&mut self, idx: usize) -> &mut u8 {
self.base.get_mut(idx)
}
fn hash(&self) -> u64 {
self.base.hash()
}
fn to_vec(&self) -> Vec<u8> {
self.base.to_vec()
}
}
impl<M> AsSlice<u8> for HitcountsMapObserver<M>
where
M: MapObserver + AsSlice<u8>,
{
#[inline]
fn as_slice(&self) -> &[u8] {
self.base.as_slice()
}
}
impl<M> AsMutSlice<u8> for HitcountsMapObserver<M>
where
M: MapObserver + AsMutSlice<u8>,
{
#[inline]
fn as_mut_slice(&mut self) -> &mut [u8] {
self.base.as_mut_slice()
}
}
impl<M> HitcountsMapObserver<M>
@ -586,19 +775,20 @@ where
#[allow(clippy::unsafe_derive_deserialize)]
pub struct MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
maps: Vec<OwnedSliceMut<'a, T>>,
intervals: IntervalTree<usize, usize>,
len: usize,
initial: T,
name: String,
iter_idx: usize,
}
impl<'a, I, S, T> Observer<I, S> for MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
Self: MapObserver<T>,
Self: MapObserver,
{
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
@ -608,7 +798,7 @@ where
impl<'a, T> Named for MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn name(&self) -> &str {
@ -618,7 +808,7 @@ where
impl<'a, T> HasLen for MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn len(&self) -> usize {
@ -626,19 +816,11 @@ where
}
}
impl<'a, T> MapObserver<T> for MultiMapObserver<'a, T>
impl<'a, T> MapObserver for MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
#[inline]
fn map(&self) -> Option<&[T]> {
None
}
#[inline]
fn map_mut(&mut self) -> Option<&mut [T]> {
None
}
type Entry = T;
#[inline]
fn get(&self, idx: usize) -> &T {
@ -706,11 +888,15 @@ where
}
Ok(())
}
fn usable_count(&self) -> usize {
self.len()
}
}
impl<'a, T> MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned,
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
/// Creates a new [`MultiMapObserver`]
#[must_use]
@ -739,6 +925,7 @@ where
len: idx,
name: name.to_string(),
initial,
iter_idx: 0,
}
}
@ -769,6 +956,31 @@ where
len: idx,
name: name.to_string(),
initial,
iter_idx: 0,
}
}
}
impl<'a, 'it, T> IntoIterator for &'it mut MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <IterMut<'it, T> as Iterator>::Item;
type IntoIter = Flatten<IterMut<'it, OwnedSliceMut<'a, T>>>;
fn into_iter(self) -> Self::IntoIter {
self.maps.iter_mut().flatten()
}
}
impl<'a, 'it, T> IntoIterator for &'it MultiMapObserver<'a, T>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
{
type Item = <Iter<'it, T> as Iterator>::Item;
type IntoIter = Flatten<Iter<'it, OwnedSliceMut<'a, T>>>;
fn into_iter(self) -> Self::IntoIter {
self.maps.iter().flatten()
}
}

View File

@ -19,34 +19,33 @@ use alloc::{
vec::Vec,
};
use core::{fmt::Debug, marker::PhantomData, time::Duration};
use num_traits::PrimInt;
use num_traits::Bounded;
use serde::{Deserialize, Serialize};
/// The calibration stage will measure the average exec time and the target's stability for this input.
#[derive(Clone, Debug)]
pub struct CalibrationStage<I, O, OT, S, T>
pub struct CalibrationStage<I, O, OT, S>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
I: Input,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata,
{
map_observer_name: String,
stage_max: usize,
phantom: PhantomData<(I, O, OT, S, T)>,
phantom: PhantomData<(I, O, OT, S)>,
}
const CAL_STAGE_START: usize = 4;
const CAL_STAGE_MAX: usize = 16;
impl<E, EM, I, O, OT, S, T, Z> Stage<E, EM, S, Z> for CalibrationStage<I, O, OT, S, T>
impl<E, EM, I, O, OT, S, Z> Stage<E, EM, S, Z> for CalibrationStage<I, O, OT, S>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
EM: EventFirer<I>,
I: Input,
O: MapObserver<T>,
O: MapObserver,
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata + HasFeedbackStates + HasClientPerfMonitor,
Z: Evaluator<E, EM, I, S>,
@ -94,8 +93,6 @@ where
.observers()
.match_name::<O>(&self.map_observer_name)
.ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))?
.map()
.unwrap()
.to_vec();
// Run CAL_STAGE_START - 1 times, increase by 2 for every time a new
@ -137,19 +134,17 @@ where
.observers()
.match_name::<O>(&self.map_observer_name)
.ok_or_else(|| Error::KeyNotFound("MapObserver not found".to_string()))?
.map()
.unwrap()
.to_vec();
let history_map = &mut state
.feedback_states_mut()
.match_name_mut::<MapFeedbackState<T>>(&self.map_observer_name)
.match_name_mut::<MapFeedbackState<O::Entry>>(&self.map_observer_name)
.unwrap()
.history_map;
for j in 0..map_len {
if map_first[j] != map[j] && history_map[j] != T::max_value() {
history_map[j] = T::max_value();
if map_first[j] != map[j] && history_map[j] != O::Entry::max_value() {
history_map[j] = O::Entry::max_value();
unstable_entries += 1;
};
}
@ -306,11 +301,10 @@ impl PowerScheduleMetadata {
crate::impl_serdeany!(PowerScheduleMetadata);
impl<I, O, OT, S, T> CalibrationStage<I, O, OT, S, T>
impl<I, O, OT, S> CalibrationStage<I, O, OT, S>
where
T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
I: Input,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasCorpus<I> + HasMetadata,
{

View File

@ -2,7 +2,6 @@
use alloc::string::{String, ToString};
use core::{fmt::Debug, marker::PhantomData};
use num_traits::PrimInt;
use crate::{
corpus::{Corpus, IsFavoredMetadata, PowerScheduleTestcaseMetaData, Testcase},
@ -34,13 +33,12 @@ const HAVOC_MAX_MULT: f64 = 64.0;
/// The mutational stage using power schedules
#[derive(Clone, Debug)]
pub struct PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z>
pub struct PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input,
M: Mutator<I, S>,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>,
@ -50,17 +48,16 @@ where
/// The employed power schedule strategy
strat: PowerSchedule,
#[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, I, O, OT, S, T, Z)>,
phantom: PhantomData<(E, EM, I, O, OT, S, Z)>,
}
impl<E, EM, I, M, O, OT, S, T, Z> MutationalStage<E, EM, I, M, S, Z>
for PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z>
impl<E, EM, I, M, O, OT, S, Z> MutationalStage<E, EM, I, M, S, Z>
for PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input,
M: Mutator<I, S>,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>,
@ -153,14 +150,12 @@ where
}
}
impl<E, EM, I, M, O, OT, S, T, Z> Stage<E, EM, S, Z>
for PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z>
impl<E, EM, I, M, O, OT, S, Z> Stage<E, EM, S, Z> for PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input,
M: Mutator<I, S>,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>,
@ -180,13 +175,12 @@ where
}
}
impl<E, EM, I, M, O, OT, S, T, Z> PowerMutationalStage<E, EM, I, M, O, OT, S, T, Z>
impl<E, EM, I, M, O, OT, S, Z> PowerMutationalStage<E, EM, I, M, O, OT, S, Z>
where
T: PrimInt + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned + Debug,
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
I: Input,
M: Mutator<I, S>,
O: MapObserver<T>,
O: MapObserver,
OT: ObserversTuple<I, S>,
S: HasClientPerfMonitor + HasCorpus<I> + HasMetadata,
Z: Evaluator<E, EM, I, S>,

View File

@ -13,7 +13,10 @@ use std::{
};
use libafl::{
bolts::shmem::{ShMem, ShMemProvider, StdShMemProvider},
bolts::{
shmem::{ShMem, ShMemProvider, StdShMemProvider},
AsSlice,
},
observers::concolic::{
serialization_format::{MessageFileReader, MessageFileWriter, DEFAULT_ENV_NAME},
EXPRESSION_PRUNING, HITMAP_ENV_NAME, NO_FLOAT_ENV_NAME, SELECTIVE_SYMBOLICATION_ENV_NAME,

View File

@ -1,6 +1,7 @@
//! Generates `DrCov` traces
use ahash::AHasher;
use libafl::{
bolts::AsSlice,
inputs::{HasTargetBytes, Input},
Error,
};

View File

@ -1,6 +1,8 @@
use libafl::inputs::{HasTargetBytes, Input};
use libafl::Error;
use libafl::{
bolts::AsSlice,
inputs::{HasTargetBytes, Input},
Error,
};
#[cfg(unix)]
use libafl_targets::drcov::DrCovBasicBlock;

View File

@ -11,6 +11,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsMutSlice,
},
corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -13,6 +13,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -12,6 +12,7 @@ use libafl::{
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
AsSlice,
},
corpus::{
CachedOnDiskCorpus, Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,

View File

@ -187,11 +187,11 @@ where
}
}
fn map(&self) -> &CmpLogMap {
fn cmp_map(&self) -> &CmpLogMap {
self.map.as_ref()
}
fn map_mut(&mut self) -> &mut CmpLogMap {
fn cmp_map_mut(&mut self) -> &mut CmpLogMap {
self.map.as_mut()
}
}