Fix as_object UB discussed in #1748 (#1751)

* Fix as_object UB discussed in #1748

* More cleanup, more less UB

* Fix fixes

* Added uninit_on_shmem api

* clippy

* fmt

* trying to fix fuzzers, libfuzzer wrapper

* Add OwnedRefMit::owned constructor, libfuzzer fix

* Some more fixes

* Add BacktaceObserver::owned fn

* fmt

* more fmt
This commit is contained in:
Dominik Maier 2023-12-22 16:49:01 +01:00 committed by GitHub
parent 4e7d2caa9f
commit c93291ab57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 245 additions and 140 deletions

View File

@ -18,8 +18,9 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_nanos, current_nanos,
ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::tuple_list,
AsSlice, AsSlice,
}; };
@ -47,10 +48,10 @@ pub fn main() {
// Create an observation channel using the signals map // Create an observation channel using the signals map
let observer = unsafe { ConstMapObserver::<u8, 3>::from_mut_ptr("signals", map_ptr) }; let observer = unsafe { ConstMapObserver::<u8, 3>::from_mut_ptr("signals", map_ptr) };
// Create a stacktrace observer // Create a stacktrace observer
let mut bt = shmem_provider.new_shmem_object::<Option<u64>>().unwrap(); let mut bt = shmem_provider.new_on_shmem::<Option<u64>>(None).unwrap();
let bt_observer = BacktraceObserver::new( let bt_observer = BacktraceObserver::new(
"BacktraceObserver", "BacktraceObserver",
unsafe { bt.as_object_mut::<Option<u64>>() }, unsafe { OwnedRefMut::from_shmem(&mut bt) },
libafl::observers::HarnessType::Child, libafl::observers::HarnessType::Child,
); );

View File

@ -37,10 +37,8 @@ pub fn main() {
// Create an observation channel using the signals map // Create an observation channel using the signals map
let observer = unsafe { ConstMapObserver::<u8, 3>::from_mut_ptr("signals", array_ptr) }; let observer = unsafe { ConstMapObserver::<u8, 3>::from_mut_ptr("signals", array_ptr) };
// Create a stacktrace observer // Create a stacktrace observer
let mut bt = None; let bt_observer = BacktraceObserver::owned(
let bt_observer = BacktraceObserver::new(
"BacktraceObserver", "BacktraceObserver",
&mut bt,
libafl::observers::HarnessType::InProcess, libafl::observers::HarnessType::InProcess,
); );

View File

@ -20,6 +20,7 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_nanos, current_nanos,
ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{unix_shmem, ShMem, ShMemProvider}, shmem::{unix_shmem, ShMem, ShMemProvider},
tuples::tuple_list, tuples::tuple_list,
@ -32,7 +33,7 @@ pub fn main() {
let mut signals = shmem_provider.new_shmem(16).unwrap(); let mut signals = shmem_provider.new_shmem(16).unwrap();
let signals_len = signals.len(); let signals_len = signals.len();
let signals_ptr = signals.as_mut_slice().as_mut_ptr(); let signals_ptr = signals.as_mut_slice().as_mut_ptr();
let mut bt = shmem_provider.new_shmem_object::<Option<u64>>().unwrap(); let mut bt = shmem_provider.new_on_shmem::<Option<u64>>(None).unwrap();
let signals_set = |idx: usize| { let signals_set = |idx: usize| {
unsafe { write(signals_ptr.add(idx), 1) }; unsafe { write(signals_ptr.add(idx), 1) };
@ -69,7 +70,7 @@ pub fn main() {
// Create a stacktrace observer // Create a stacktrace observer
let bt_observer = BacktraceObserver::new( let bt_observer = BacktraceObserver::new(
"BacktraceObserver", "BacktraceObserver",
unsafe { bt.as_object_mut::<Option<u64>>() }, unsafe { OwnedRefMut::from_shmem(&mut bt) },
libafl::observers::HarnessType::Child, libafl::observers::HarnessType::Child,
); );

View File

@ -61,10 +61,8 @@ pub fn main() {
// Create an observation channel using the signals map // Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) };
// Create a stacktrace observer to add the observers tuple // Create a stacktrace observer to add the observers tuple
let mut bt = None; let bt_observer = BacktraceObserver::owned(
let bt_observer = BacktraceObserver::new(
"BacktraceObserver", "BacktraceObserver",
&mut bt,
libafl::observers::HarnessType::InProcess, libafl::observers::HarnessType::InProcess,
); );

View File

@ -209,9 +209,7 @@ fn fuzz(
let edges = edges_shmem.as_mut_slice(); let edges = edges_shmem.as_mut_slice();
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() }; unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
let mut cmp_shmem = shmem_provider let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap();
.new_shmem(core::mem::size_of::<CmpLogMap>())
.unwrap();
let cmplog = cmp_shmem.as_mut_slice(); let cmplog = cmp_shmem.as_mut_slice();
// Beginning of a page should be properly aligned. // Beginning of a page should be properly aligned.

View File

@ -34,6 +34,7 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_nanos, current_time, current_nanos, current_time,
ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
@ -204,6 +205,7 @@ pub fn main() {
} }
/// The actual fuzzer /// The actual fuzzer
#[allow(clippy::too_many_arguments)]
fn fuzz( fn fuzz(
corpus_dir: PathBuf, corpus_dir: PathBuf,
objective_dir: PathBuf, objective_dir: PathBuf,
@ -340,12 +342,10 @@ fn fuzz(
if let Some(exec) = &cmplog_exec { if let Some(exec) = &cmplog_exec {
// The cmplog map shared between observer and executor // The cmplog map shared between observer and executor
let mut cmplog_shmem = shmem_provider let mut cmplog_shmem = shmem_provider.uninit_on_shmem::<AFLppCmpLogMap>().unwrap();
.new_shmem(core::mem::size_of::<AFLppCmpLogMap>())
.unwrap();
// let the forkserver know the shmid // let the forkserver know the shmid
cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap();
let cmpmap = unsafe { cmplog_shmem.as_object_mut::<AFLppCmpLogMap>() }; let cmpmap = unsafe { OwnedRefMut::<AFLppCmpLogMap>::from_shmem(&mut cmplog_shmem) };
let cmplog_observer = StdCmpValuesObserver::new("cmplog", cmpmap, true); let cmplog_observer = StdCmpValuesObserver::new("cmplog", cmpmap, true);

View File

@ -34,6 +34,7 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_nanos, current_time, current_nanos, current_time,
ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, UnixShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
@ -207,6 +208,7 @@ pub fn main() {
} }
/// The actual fuzzer /// The actual fuzzer
#[allow(clippy::too_many_arguments)]
fn fuzz( fn fuzz(
corpus_dir: PathBuf, corpus_dir: PathBuf,
objective_dir: PathBuf, objective_dir: PathBuf,
@ -344,12 +346,10 @@ fn fuzz(
if let Some(exec) = &cmplog_exec { if let Some(exec) = &cmplog_exec {
// The cmplog map shared between observer and executor // The cmplog map shared between observer and executor
let mut cmplog_shmem = shmem_provider let mut cmplog_shmem = shmem_provider.uninit_on_shmem::<AFLppCmpLogMap>().unwrap();
.new_shmem(core::mem::size_of::<AFLppCmpLogMap>())
.unwrap();
// let the forkserver know the shmid // let the forkserver know the shmid
cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap(); cmplog_shmem.write_to_env("__AFL_CMPLOG_SHM_ID").unwrap();
let cmpmap = unsafe { cmplog_shmem.as_object_mut::<AFLppCmpLogMap>() }; let cmpmap = unsafe { OwnedRefMut::from_shmem(&mut cmplog_shmem) };
let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true); let cmplog_observer = AFLppCmpLogObserver::new("cmplog", cmpmap, true);

View File

@ -333,11 +333,11 @@ where
{ {
/// Creates a new [`StdCmpObserver`] with the given name and map. /// Creates a new [`StdCmpObserver`] with the given name and map.
#[must_use] #[must_use]
pub fn new(name: &'static str, map: &'a mut CM, add_meta: bool) -> Self { pub fn new(name: &'static str, map: OwnedRefMut<'a, CM>, add_meta: bool) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: None, size: None,
cmp_map: OwnedRefMut::Ref(map), cmp_map: map,
add_meta, add_meta,
data: M::Data::default(), data: M::Data::default(),
phantom: PhantomData, phantom: PhantomData,
@ -347,11 +347,16 @@ where
/// Creates a new [`StdCmpObserver`] with the given name, map, and auxiliary data used to /// Creates a new [`StdCmpObserver`] with the given name, map, and auxiliary data used to
/// populate metadata /// populate metadata
#[must_use] #[must_use]
pub fn with_data(name: &'static str, map: &'a mut CM, add_meta: bool, data: M::Data) -> Self { pub fn with_data(
name: &'static str,
cmp_map: OwnedRefMut<'a, CM>,
add_meta: bool,
data: M::Data,
) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: None, size: None,
cmp_map: OwnedRefMut::Ref(map), cmp_map,
add_meta, add_meta,
data, data,
phantom: PhantomData, phantom: PhantomData,
@ -362,14 +367,14 @@ where
#[must_use] #[must_use]
pub fn with_size( pub fn with_size(
name: &'static str, name: &'static str,
map: &'a mut CM, cmp_map: OwnedRefMut<'a, CM>,
add_meta: bool, add_meta: bool,
size: &'a mut usize, size: OwnedRefMut<'a, usize>,
) -> Self { ) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)), size: Some(size),
cmp_map: OwnedRefMut::Ref(map), cmp_map,
add_meta, add_meta,
data: M::Data::default(), data: M::Data::default(),
phantom: PhantomData, phantom: PhantomData,
@ -381,15 +386,15 @@ where
#[must_use] #[must_use]
pub fn with_size_data( pub fn with_size_data(
name: &'static str, name: &'static str,
map: &'a mut CM, cmp_map: OwnedRefMut<'a, CM>,
add_meta: bool, add_meta: bool,
data: M::Data, data: M::Data,
size: &'a mut usize, size: OwnedRefMut<'a, usize>,
) -> Self { ) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)), size: Some(size),
cmp_map: OwnedRefMut::Ref(map), cmp_map,
add_meta, add_meta,
data, data,
phantom: PhantomData, phantom: PhantomData,

View File

@ -127,12 +127,12 @@ impl<'a> BacktraceObserver<'a> {
#[must_use] #[must_use]
pub fn new( pub fn new(
observer_name: &str, observer_name: &str,
backtrace_hash: &'a mut Option<u64>, backtrace_hash: OwnedRefMut<'a, Option<u64>>,
harness_type: HarnessType, harness_type: HarnessType,
) -> Self { ) -> Self {
Self { Self {
observer_name: observer_name.to_string(), observer_name: observer_name.to_string(),
hash: OwnedRefMut::Ref(backtrace_hash), hash: backtrace_hash,
harness_type, harness_type,
} }
} }
@ -142,17 +142,23 @@ impl<'a> BacktraceObserver<'a> {
#[must_use] #[must_use]
pub fn new( pub fn new(
observer_name: &str, observer_name: &str,
backtrace_hash: &'a mut Option<u64>, backtrace_hash: OwnedRefMut<'a, Option<u64>>,
harness_type: HarnessType, harness_type: HarnessType,
) -> Self { ) -> Self {
init_ignored_frames!("rust", "cpp", "go"); init_ignored_frames!("rust", "cpp", "go");
Self { Self {
observer_name: observer_name.to_string(), observer_name: observer_name.to_string(),
hash: OwnedRefMut::Ref(backtrace_hash), hash: backtrace_hash,
harness_type, harness_type,
} }
} }
/// Creates a new [`BacktraceObserver`] with the given name, owning a new `backtrace_hash` variable.
#[must_use]
pub fn owned(observer_name: &str, harness_type: HarnessType) -> Self {
Self::new(observer_name, OwnedRefMut::owned(None), harness_type)
}
/// Updates the hash value of this observer. /// Updates the hash value of this observer.
fn update_hash(&mut self, hash: u64) { fn update_hash(&mut self, hash: u64) {
*self.hash.as_mut() = Some(hash); *self.hash.as_mut() = Some(hash);

View File

@ -40,10 +40,10 @@ where
{ {
/// Creates a new [`ValueObserver`] with the given name. /// Creates a new [`ValueObserver`] with the given name.
#[must_use] #[must_use]
pub fn new(name: &'static str, value: &'a T) -> Self { pub fn new(name: &'static str, value: OwnedRef<'a, T>) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
value: OwnedRef::Ref(value), value,
} }
} }
@ -65,6 +65,7 @@ where
T: Clone, T: Clone,
{ {
match self.value { match self.value {
OwnedRef::RefRaw(r, _) => unsafe { (*r).clone() },
OwnedRef::Ref(r) => r.clone(), OwnedRef::Ref(r) => r.clone(),
OwnedRef::Owned(v) => *v, OwnedRef::Owned(v) => *v,
} }
@ -119,10 +120,10 @@ where
{ {
/// Creates a new [`RefCellValueObserver`] with the given name. /// Creates a new [`RefCellValueObserver`] with the given name.
#[must_use] #[must_use]
pub fn new(name: &'static str, value: &'a RefCell<T>) -> Self { pub fn new(name: &'static str, value: OwnedRef<'a, RefCell<T>>) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
value: OwnedRef::Ref(value), value,
} }
} }
@ -147,6 +148,7 @@ where
T: Clone, T: Clone,
{ {
match self.value { match self.value {
OwnedRef::RefRaw(r, _) => unsafe { (*r).borrow().deref().clone() },
OwnedRef::Ref(r) => r.borrow().deref().clone(), OwnedRef::Ref(r) => r.borrow().deref().clone(),
OwnedRef::Owned(v) => v.borrow().clone(), OwnedRef::Owned(v) => v.borrow().clone(),
} }

View File

@ -10,7 +10,28 @@ use core::{clone::Clone, fmt::Debug, slice};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{AsMutSlice, AsSlice, IntoOwned, Truncate}; use crate::{shmem::ShMem, AsMutSlice, AsSlice, IntoOwned, Truncate};
/// Private part of the unsafe marker, making sure this cannot be initialized directly.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
struct UnsafeMarkerInner;
/// A struct or enum containing this [`UnsafeMarker`] cannot directly be instantiated.
/// Usually, this means you'll have to use a constructor like `unsafe { Self::new() }` or similar.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct UnsafeMarker(UnsafeMarkerInner);
impl UnsafeMarker {
/// Return a new unsafe marker.
/// This usually means you're about to do something unsafe.
///
/// # Safety
/// Instantiating an [`UnsafeMarker`] isn't unsafe, but the location you need it for
/// will likely have potential unsafety.
unsafe fn new() -> Self {
Self(UnsafeMarkerInner)
}
}
impl<'a, T> Truncate for &'a [T] { impl<'a, T> Truncate for &'a [T] {
fn truncate(&mut self, len: usize) { fn truncate(&mut self, len: usize) {
@ -32,12 +53,54 @@ pub enum OwnedRef<'a, T>
where where
T: 'a + ?Sized, T: 'a + ?Sized,
{ {
/// A pointer to a type
RefRaw(*const T, UnsafeMarker),
/// A ref to a type /// A ref to a type
Ref(&'a T), Ref(&'a T),
/// An owned [`Box`] of a type /// An owned [`Box`] of a type
Owned(Box<T>), Owned(Box<T>),
} }
impl<'a, T> OwnedRef<'a, T>
where
T: 'a + ?Sized,
{
/// Returns a new [`OwnedRef`], wrapping a pointer of type `T`.
///
/// # Safety
/// The pointer needs to point to a valid object of type `T`.
/// Any use of this [`OwnedRef`] will dereference the pointer accordingly.
pub unsafe fn from_ptr(ptr: *const T) -> Self {
assert!(
!ptr.is_null(),
"Null pointer passed to OwnedRef::ref_raw constructor!"
);
Self::RefRaw(ptr, UnsafeMarker::new())
}
}
impl<'a, T> OwnedRef<'a, T>
where
T: Sized + 'static,
{
/// Returns a new [`OwnedRef`], pointing to the given [`ShMem`].
///
/// # Panics
/// Panics if the given shared mem is too small
///
/// # Safety
/// The shared memory needs to start with a valid object of type `T`.
/// Any use of this [`OwnedRef`] will dereference a pointer to the shared memory accordingly.
pub unsafe fn from_shmem<S: ShMem>(shmem: &mut S) -> Self {
Self::from_ptr(shmem.as_mut_ptr_of().unwrap())
}
/// Returns a new [`OwnedRef`], owning the given value.
pub fn owned(val: T) -> Self {
Self::Owned(Box::new(val))
}
}
impl<'a, T> Serialize for OwnedRef<'a, T> impl<'a, T> Serialize for OwnedRef<'a, T>
where where
T: 'a + ?Sized + Serialize, T: 'a + ?Sized + Serialize,
@ -47,6 +110,7 @@ where
S: Serializer, S: Serializer,
{ {
match self { match self {
OwnedRef::RefRaw(r, _) => unsafe { (*r).as_ref().unwrap() }.serialize(se),
OwnedRef::Ref(r) => r.serialize(se), OwnedRef::Ref(r) => r.serialize(se),
OwnedRef::Owned(b) => b.serialize(se), OwnedRef::Owned(b) => b.serialize(se),
} }
@ -73,6 +137,7 @@ where
#[must_use] #[must_use]
fn as_ref(&self) -> &T { fn as_ref(&self) -> &T {
match self { match self {
OwnedRef::RefRaw(r, _) => unsafe { (*r).as_ref().unwrap() },
OwnedRef::Ref(r) => r, OwnedRef::Ref(r) => r,
OwnedRef::Owned(v) => v.as_ref(), OwnedRef::Owned(v) => v.as_ref(),
} }
@ -86,7 +151,7 @@ where
#[must_use] #[must_use]
fn is_owned(&self) -> bool { fn is_owned(&self) -> bool {
match self { match self {
OwnedRef::Ref(_) => false, OwnedRef::RefRaw(..) | OwnedRef::Ref(_) => false,
OwnedRef::Owned(_) => true, OwnedRef::Owned(_) => true,
} }
} }
@ -94,6 +159,9 @@ where
#[must_use] #[must_use]
fn into_owned(self) -> Self { fn into_owned(self) -> Self {
match self { match self {
OwnedRef::RefRaw(r, _) => {
OwnedRef::Owned(Box::new(unsafe { r.as_ref().unwrap().clone() }))
}
OwnedRef::Ref(r) => OwnedRef::Owned(Box::new(r.clone())), OwnedRef::Ref(r) => OwnedRef::Owned(Box::new(r.clone())),
OwnedRef::Owned(v) => OwnedRef::Owned(v), OwnedRef::Owned(v) => OwnedRef::Owned(v),
} }
@ -102,13 +170,61 @@ where
/// Wrap a mutable reference and convert to a Box on serialize /// Wrap a mutable reference and convert to a Box on serialize
#[derive(Debug)] #[derive(Debug)]
pub enum OwnedRefMut<'a, T: 'a + ?Sized> { pub enum OwnedRefMut<'a, T>
where
T: 'a + ?Sized,
{
/// A mutable pointer to a type
RefRaw(*mut T, UnsafeMarker),
/// A mutable ref to a type /// A mutable ref to a type
Ref(&'a mut T), Ref(&'a mut T),
/// An owned [`Box`] of a type /// An owned [`Box`] of a type
Owned(Box<T>), Owned(Box<T>),
} }
impl<'a, T> OwnedRefMut<'a, T>
where
T: 'a + ?Sized,
{
/// Returns a new [`OwnedRefMut`], wrapping a mutable pointer.
///
/// # Panics
/// Panics if the given pointer is `null`
///
/// # Safety
/// The pointer needs to point to a valid object of type `T`.
/// Any use of this [`OwnedRefMut`] will dereference the pointer accordingly.
pub unsafe fn from_mut_ptr(ptr: *mut T) -> Self {
assert!(
!ptr.is_null(),
"Null pointer passed to OwnedRefMut::from_mut_ptr constructor!"
);
Self::RefRaw(ptr, UnsafeMarker::new())
}
}
impl<'a, T> OwnedRefMut<'a, T>
where
T: Sized + 'static,
{
/// Returns a new [`OwnedRefMut`], pointing to the given [`ShMem`].
///
/// # Panics
/// Panics if the given shared mem is too small
///
/// # Safety
/// The shared memory needs to start with a valid object of type `T`.
/// Any use of this [`OwnedRefMut`] will dereference a pointer to the shared memory accordingly.
pub unsafe fn from_shmem<S: ShMem>(shmem: &mut S) -> Self {
Self::from_mut_ptr(shmem.as_mut_ptr_of().unwrap())
}
/// Returns a new [`OwnedRefMut`], owning the given value.
pub fn owned(val: T) -> Self {
Self::Owned(Box::new(val))
}
}
impl<'a, T: 'a + ?Sized + Serialize> Serialize for OwnedRefMut<'a, T> { impl<'a, T: 'a + ?Sized + Serialize> Serialize for OwnedRefMut<'a, T> {
fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
where where
@ -116,6 +232,7 @@ impl<'a, T: 'a + ?Sized + Serialize> Serialize for OwnedRefMut<'a, T> {
{ {
match self { match self {
OwnedRefMut::Ref(r) => r.serialize(se), OwnedRefMut::Ref(r) => r.serialize(se),
OwnedRefMut::RefRaw(r, _) => unsafe { r.as_ref().unwrap().serialize(se) },
OwnedRefMut::Owned(b) => b.serialize(se), OwnedRefMut::Owned(b) => b.serialize(se),
} }
} }
@ -137,6 +254,7 @@ impl<'a, T: Sized> AsRef<T> for OwnedRefMut<'a, T> {
#[must_use] #[must_use]
fn as_ref(&self) -> &T { fn as_ref(&self) -> &T {
match self { match self {
OwnedRefMut::RefRaw(r, _) => unsafe { r.as_ref().unwrap() },
OwnedRefMut::Ref(r) => r, OwnedRefMut::Ref(r) => r,
OwnedRefMut::Owned(v) => v.as_ref(), OwnedRefMut::Owned(v) => v.as_ref(),
} }
@ -147,6 +265,7 @@ impl<'a, T: Sized> AsMut<T> for OwnedRefMut<'a, T> {
#[must_use] #[must_use]
fn as_mut(&mut self) -> &mut T { fn as_mut(&mut self) -> &mut T {
match self { match self {
OwnedRefMut::RefRaw(r, _) => unsafe { r.as_mut().unwrap() },
OwnedRefMut::Ref(r) => r, OwnedRefMut::Ref(r) => r,
OwnedRefMut::Owned(v) => v.as_mut(), OwnedRefMut::Owned(v) => v.as_mut(),
} }
@ -160,7 +279,7 @@ where
#[must_use] #[must_use]
fn is_owned(&self) -> bool { fn is_owned(&self) -> bool {
match self { match self {
OwnedRefMut::Ref(_) => false, OwnedRefMut::RefRaw(..) | OwnedRefMut::Ref(_) => false,
OwnedRefMut::Owned(_) => true, OwnedRefMut::Owned(_) => true,
} }
} }
@ -168,6 +287,9 @@ where
#[must_use] #[must_use]
fn into_owned(self) -> Self { fn into_owned(self) -> Self {
match self { match self {
OwnedRefMut::RefRaw(r, _) => unsafe {
OwnedRefMut::Owned(Box::new(r.as_ref().unwrap().clone()))
},
OwnedRefMut::Ref(r) => OwnedRefMut::Owned(Box::new(r.clone())), OwnedRefMut::Ref(r) => OwnedRefMut::Owned(Box::new(r.clone())),
OwnedRefMut::Owned(v) => OwnedRefMut::Owned(v), OwnedRefMut::Owned(v) => OwnedRefMut::Owned(v),
} }
@ -178,7 +300,7 @@ where
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
enum OwnedSliceInner<'a, T: 'a + Sized> { enum OwnedSliceInner<'a, T: 'a + Sized> {
/// A ref to a raw slice and length /// A ref to a raw slice and length
RefRaw(*const T, usize), RefRaw(*const T, usize, UnsafeMarker),
/// A ref to a slice /// A ref to a slice
Ref(&'a [T]), Ref(&'a [T]),
/// A ref to an owned [`Vec`] /// A ref to an owned [`Vec`]
@ -191,7 +313,7 @@ impl<'a, T: 'a + Sized + Serialize> Serialize for OwnedSliceInner<'a, T> {
S: Serializer, S: Serializer,
{ {
match self { match self {
OwnedSliceInner::RefRaw(rr, len) => unsafe { OwnedSliceInner::RefRaw(rr, len, _) => unsafe {
slice::from_raw_parts(*rr, *len).serialize(se) slice::from_raw_parts(*rr, *len).serialize(se)
}, },
OwnedSliceInner::Ref(r) => r.serialize(se), OwnedSliceInner::Ref(r) => r.serialize(se),
@ -239,14 +361,14 @@ impl<'a, T> OwnedSlice<'a, T> {
#[must_use] #[must_use]
pub unsafe fn from_raw_parts(ptr: *const T, len: usize) -> Self { pub unsafe fn from_raw_parts(ptr: *const T, len: usize) -> Self {
Self { Self {
inner: OwnedSliceInner::RefRaw(ptr, len), inner: OwnedSliceInner::RefRaw(ptr, len, UnsafeMarker::new()),
} }
} }
/// Truncate the inner slice or vec returning the old size on success or `None` on failure /// Truncate the inner slice or vec returning the old size on success or `None` on failure
pub fn truncate(&mut self, new_len: usize) -> Option<usize> { pub fn truncate(&mut self, new_len: usize) -> Option<usize> {
match &mut self.inner { match &mut self.inner {
OwnedSliceInner::RefRaw(_rr, len) => { OwnedSliceInner::RefRaw(_rr, len, _) => {
let tmp = *len; let tmp = *len;
if new_len <= tmp { if new_len <= tmp {
*len = new_len; *len = new_len;
@ -323,7 +445,9 @@ impl<'a, T> From<OwnedMutSlice<'a, T>> for OwnedSlice<'a, T> {
fn from(mut_slice: OwnedMutSlice<'a, T>) -> Self { fn from(mut_slice: OwnedMutSlice<'a, T>) -> Self {
Self { Self {
inner: match mut_slice.inner { inner: match mut_slice.inner {
OwnedMutSliceInner::RefRaw(ptr, len) => OwnedSliceInner::RefRaw(ptr as _, len), OwnedMutSliceInner::RefRaw(ptr, len, unsafe_marker) => {
OwnedSliceInner::RefRaw(ptr as _, len, unsafe_marker)
}
OwnedMutSliceInner::Ref(r) => OwnedSliceInner::Ref(r as _), OwnedMutSliceInner::Ref(r) => OwnedSliceInner::Ref(r as _),
OwnedMutSliceInner::Owned(v) => OwnedSliceInner::Owned(v), OwnedMutSliceInner::Owned(v) => OwnedSliceInner::Owned(v),
}, },
@ -338,7 +462,7 @@ impl<'a, T: Sized> AsSlice for OwnedSlice<'a, T> {
fn as_slice(&self) -> &[T] { fn as_slice(&self) -> &[T] {
match &self.inner { match &self.inner {
OwnedSliceInner::Ref(r) => r, OwnedSliceInner::Ref(r) => r,
OwnedSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) }, OwnedSliceInner::RefRaw(rr, len, _) => unsafe { slice::from_raw_parts(*rr, *len) },
OwnedSliceInner::Owned(v) => v.as_slice(), OwnedSliceInner::Owned(v) => v.as_slice(),
} }
} }
@ -351,7 +475,7 @@ where
#[must_use] #[must_use]
fn is_owned(&self) -> bool { fn is_owned(&self) -> bool {
match self.inner { match self.inner {
OwnedSliceInner::RefRaw(_, _) | OwnedSliceInner::Ref(_) => false, OwnedSliceInner::RefRaw(..) | OwnedSliceInner::Ref(_) => false,
OwnedSliceInner::Owned(_) => true, OwnedSliceInner::Owned(_) => true,
} }
} }
@ -359,7 +483,7 @@ where
#[must_use] #[must_use]
fn into_owned(self) -> Self { fn into_owned(self) -> Self {
match self.inner { match self.inner {
OwnedSliceInner::RefRaw(rr, len) => Self { OwnedSliceInner::RefRaw(rr, len, _) => Self {
inner: OwnedSliceInner::Owned(unsafe { slice::from_raw_parts(rr, len).to_vec() }), inner: OwnedSliceInner::Owned(unsafe { slice::from_raw_parts(rr, len).to_vec() }),
}, },
OwnedSliceInner::Ref(r) => Self { OwnedSliceInner::Ref(r) => Self {
@ -392,7 +516,7 @@ where
#[derive(Debug)] #[derive(Debug)]
pub enum OwnedMutSliceInner<'a, T: 'a + Sized> { pub enum OwnedMutSliceInner<'a, T: 'a + Sized> {
/// A raw ptr to a memory location and a length /// A raw ptr to a memory location and a length
RefRaw(*mut T, usize), RefRaw(*mut T, usize, UnsafeMarker),
/// A ptr to a mutable slice of the type /// A ptr to a mutable slice of the type
Ref(&'a mut [T]), Ref(&'a mut [T]),
/// An owned [`Vec`] of the type /// An owned [`Vec`] of the type
@ -405,7 +529,7 @@ impl<'a, T: 'a + Sized + Serialize> Serialize for OwnedMutSliceInner<'a, T> {
S: Serializer, S: Serializer,
{ {
match self { match self {
OwnedMutSliceInner::RefRaw(rr, len) => { OwnedMutSliceInner::RefRaw(rr, len, _) => {
unsafe { slice::from_raw_parts_mut(*rr, *len) }.serialize(se) unsafe { slice::from_raw_parts_mut(*rr, *len) }.serialize(se)
} }
OwnedMutSliceInner::Ref(r) => r.serialize(se), OwnedMutSliceInner::Ref(r) => r.serialize(se),
@ -466,7 +590,7 @@ impl<'a, T: 'a + Sized> OwnedMutSlice<'a, T> {
} }
} else { } else {
Self { Self {
inner: OwnedMutSliceInner::RefRaw(ptr, len), inner: OwnedMutSliceInner::RefRaw(ptr, len, UnsafeMarker::new()),
} }
} }
} }
@ -474,7 +598,7 @@ impl<'a, T: 'a + Sized> OwnedMutSlice<'a, T> {
/// Truncate the inner slice or vec returning the old size on success or `None` on failure /// Truncate the inner slice or vec returning the old size on success or `None` on failure
pub fn truncate(&mut self, new_len: usize) -> Option<usize> { pub fn truncate(&mut self, new_len: usize) -> Option<usize> {
match &mut self.inner { match &mut self.inner {
OwnedMutSliceInner::RefRaw(_rr, len) => { OwnedMutSliceInner::RefRaw(_rr, len, _) => {
let tmp = *len; let tmp = *len;
if new_len <= tmp { if new_len <= tmp {
*len = new_len; *len = new_len;
@ -521,7 +645,7 @@ impl<'a, T: Sized> AsSlice for OwnedMutSlice<'a, T> {
#[must_use] #[must_use]
fn as_slice(&self) -> &[T] { fn as_slice(&self) -> &[T] {
match &self.inner { match &self.inner {
OwnedMutSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts(*rr, *len) }, OwnedMutSliceInner::RefRaw(rr, len, _) => unsafe { slice::from_raw_parts(*rr, *len) },
OwnedMutSliceInner::Ref(r) => r, OwnedMutSliceInner::Ref(r) => r,
OwnedMutSliceInner::Owned(v) => v.as_slice(), OwnedMutSliceInner::Owned(v) => v.as_slice(),
} }
@ -533,7 +657,9 @@ impl<'a, T: Sized> AsMutSlice for OwnedMutSlice<'a, T> {
#[must_use] #[must_use]
fn as_mut_slice(&mut self) -> &mut [T] { fn as_mut_slice(&mut self) -> &mut [T] {
match &mut self.inner { match &mut self.inner {
OwnedMutSliceInner::RefRaw(rr, len) => unsafe { slice::from_raw_parts_mut(*rr, *len) }, OwnedMutSliceInner::RefRaw(rr, len, _) => unsafe {
slice::from_raw_parts_mut(*rr, *len)
},
OwnedMutSliceInner::Ref(r) => r, OwnedMutSliceInner::Ref(r) => r,
OwnedMutSliceInner::Owned(v) => v.as_mut_slice(), OwnedMutSliceInner::Owned(v) => v.as_mut_slice(),
} }
@ -547,7 +673,7 @@ where
#[must_use] #[must_use]
fn is_owned(&self) -> bool { fn is_owned(&self) -> bool {
match self.inner { match self.inner {
OwnedMutSliceInner::RefRaw(_, _) | OwnedMutSliceInner::Ref(_) => false, OwnedMutSliceInner::RefRaw(..) | OwnedMutSliceInner::Ref(_) => false,
OwnedMutSliceInner::Owned(_) => true, OwnedMutSliceInner::Owned(_) => true,
} }
} }
@ -555,7 +681,7 @@ where
#[must_use] #[must_use]
fn into_owned(self) -> Self { fn into_owned(self) -> Self {
let vec = match self.inner { let vec = match self.inner {
OwnedMutSliceInner::RefRaw(rr, len) => unsafe { OwnedMutSliceInner::RefRaw(rr, len, _) => unsafe {
slice::from_raw_parts_mut(rr, len).to_vec() slice::from_raw_parts_mut(rr, len).to_vec()
}, },
OwnedMutSliceInner::Ref(r) => r.to_vec(), OwnedMutSliceInner::Ref(r) => r.to_vec(),

View File

@ -3,11 +3,11 @@
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use alloc::{rc::Rc, string::ToString}; use alloc::{rc::Rc, string::ToString};
use core::fmt::Debug;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use core::fmt::Display; use core::fmt::Display;
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
use core::{cell::RefCell, fmt, mem::ManuallyDrop}; use core::{cell::RefCell, fmt, mem::ManuallyDrop};
use core::{fmt::Debug, mem};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::env; use std::env;
#[cfg(all(unix, feature = "std", not(target_os = "haiku")))] #[cfg(all(unix, feature = "std", not(target_os = "haiku")))]
@ -204,52 +204,24 @@ pub trait ShMem: Sized + Debug + Clone + AsSlice<Entry = u8> + AsMutSlice<Entry
self.len() == 0 self.len() == 0
} }
/// Convert to an owned object reference /// Convert to a ptr of a given type, checking the size.
/// /// If the map is too small, returns `None`
/// # Safety fn as_ptr_of<T: Sized>(&self) -> Option<*const T> {
/// This function is not safe as the object may be not initialized. if self.len() >= mem::size_of::<T>() {
/// The user is responsible to initialize the object with something like Some(self.as_slice().as_ptr() as *const T)
/// `*shmem.as_object_mut::<T>() = T::new();` } else {
unsafe fn as_object<T: Sized + 'static>(&self) -> &T { None
assert!(self.len() >= core::mem::size_of::<T>()); }
(self.as_slice().as_ptr() as *const () as *const T)
.as_ref()
.unwrap()
} }
/// Convert to an owned object mutable reference /// Convert to a mut ptr of a given type, checking the size.
/// /// If the map is too small, returns `None`
/// # Safety fn as_mut_ptr_of<T: Sized>(&mut self) -> Option<*mut T> {
/// This function is not safe as the object may be not initialized. if self.len() >= mem::size_of::<T>() {
/// The user is responsible to initialize the object with something like Some(self.as_mut_slice().as_mut_ptr() as *mut T)
/// `*shmem.as_object_mut::<T>() = T::new();` } else {
unsafe fn as_object_mut<T: Sized + 'static>(&mut self) -> &mut T { None
assert!(self.len() >= core::mem::size_of::<T>());
(self.as_mut_slice().as_mut_ptr() as *mut () as *mut T)
.as_mut()
.unwrap()
} }
/// Convert to a slice of type &\[T\]
///
/// # Safety
/// This function is not safe as the object may be not initialized.
/// The user is responsible to initialize the objects in the slice
unsafe fn as_objects_slice<T: Sized + 'static>(&self, len: usize) -> &[T] {
assert!(self.len() >= core::mem::size_of::<T>() * len);
let ptr = self.as_slice().as_ptr() as *const () as *const T;
core::slice::from_raw_parts(ptr, len)
}
/// Convert to a slice of type &mut \[T\]
///
/// # Safety
/// This function is not safe as the object may be not initialized.
/// The user is responsible to initialize the objects in the slice
unsafe fn as_objects_slice_mut<T: Sized + 'static>(&mut self, len: usize) -> &mut [T] {
assert!(self.len() >= core::mem::size_of::<T>() * len);
let ptr = self.as_mut_slice().as_mut_ptr() as *mut () as *mut T;
core::slice::from_raw_parts_mut(ptr, len)
} }
/// Get the description of the shared memory mapping /// Get the description of the shared memory mapping
@ -287,25 +259,20 @@ pub trait ShMemProvider: Clone + Default + Debug {
/// Get a mapping given its id and size /// Get a mapping given its id and size
fn shmem_from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::ShMem, Error>; fn shmem_from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::ShMem, Error>;
/// Create a new shared memory mapping to hold an object of the given type /// Create a new shared memory mapping to hold an object of the given type, and initializes it with the given value.
fn new_shmem_object<T: Sized + 'static>(&mut self) -> Result<Self::ShMem, Error> { fn new_on_shmem<T: Sized + 'static>(&mut self, value: T) -> Result<Self::ShMem, Error> {
self.new_shmem(core::mem::size_of::<T>()) self.uninit_on_shmem::<T>().map(|mut shmem| {
// # Safety
// The map has been created at this point in time, and is large enough.
// The map is fresh from the OS and, hence, the pointer should be properly aligned for any object.
unsafe { shmem.as_mut_ptr_of::<T>().unwrap().write_volatile(value) };
shmem
})
} }
/// Create a new shared memory mapping to hold an array of objects of the given type /// Create a new shared memory mapping to hold an object of the given type, and initializes it with the given value.
fn new_shmem_objects_array<T: Sized + 'static>( fn uninit_on_shmem<T: Sized + 'static>(&mut self) -> Result<Self::ShMem, Error> {
&mut self, self.new_shmem(mem::size_of::<T>())
len: usize,
) -> Result<Self::ShMem, Error> {
self.new_shmem(core::mem::size_of::<T>() * len)
}
/// Get a mapping given its id to hold an object of the given type
fn shmem_object_from_id<T: Sized + 'static>(
&mut self,
id: ShMemId,
) -> Result<Self::ShMem, Error> {
self.shmem_from_id_and_size(id, core::mem::size_of::<T>())
} }
/// Get a mapping given a description /// Get a mapping given a description

View File

@ -115,8 +115,6 @@ use mimalloc::MiMalloc;
#[cfg(feature = "mimalloc")] #[cfg(feature = "mimalloc")]
static GLOBAL: MiMalloc = MiMalloc; static GLOBAL: MiMalloc = MiMalloc;
static mut BACKTRACE: Option<u64> = None;
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
struct CustomMutationStatus { struct CustomMutationStatus {
std_mutational: bool, std_mutational: bool,
@ -184,11 +182,13 @@ macro_rules! fuzz_with {
use rand::{thread_rng, RngCore}; use rand::{thread_rng, RngCore};
use std::{env::temp_dir, fs::create_dir, path::PathBuf}; use std::{env::temp_dir, fs::create_dir, path::PathBuf};
use crate::{BACKTRACE, CustomMutationStatus}; use crate::{
use crate::corpus::{ArtifactCorpus, LibfuzzerCorpus}; CustomMutationStatus,
use crate::feedbacks::{LibfuzzerCrashCauseFeedback, LibfuzzerKeepFeedback, ShrinkMapFeedback}; corpus::{ArtifactCorpus, LibfuzzerCorpus},
use crate::misc::should_use_grimoire; feedbacks::{LibfuzzerCrashCauseFeedback, LibfuzzerKeepFeedback, ShrinkMapFeedback},
use crate::observers::{MappedEdgeMapObserver, SizeValueObserver}; misc::should_use_grimoire,
observers::{MappedEdgeMapObserver, SizeValueObserver},
};
let edge_maker = &$edge_maker; let edge_maker = &$edge_maker;
@ -213,9 +213,8 @@ macro_rules! fuzz_with {
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
// Create a stacktrace observer // Create a stacktrace observer
let backtrace_observer = BacktraceObserver::new( let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver", "BacktraceObserver",
unsafe { &mut BACKTRACE },
if $options.forks().is_some() || $options.tui() { libafl::observers::HarnessType::Child } else { libafl::observers::HarnessType::InProcess } if $options.forks().is_some() || $options.tui() { libafl::observers::HarnessType::Child } else { libafl::observers::HarnessType::InProcess }
); );

View File

@ -428,7 +428,7 @@ pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap {
pub use libafl_cmplog_map as CMPLOG_MAP; pub use libafl_cmplog_map as CMPLOG_MAP;
pub use libafl_cmplog_map_extended as CMPLOG_MAP_EXTENDED; pub use libafl_cmplog_map_extended as CMPLOG_MAP_EXTENDED;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
#[repr(C, packed)] #[repr(C, packed)]
/// Comparison map compatible with AFL++ cmplog instrumentation /// Comparison map compatible with AFL++ cmplog instrumentation
pub struct AFLppCmpLogMap { pub struct AFLppCmpLogMap {

View File

@ -179,11 +179,15 @@ where
{ {
/// Creates a new [`AFLppCmpLogObserver`] with the given name and map. /// Creates a new [`AFLppCmpLogObserver`] with the given name and map.
#[must_use] #[must_use]
pub fn new(name: &'static str, map: &'a mut AFLppCmpLogMap, add_meta: bool) -> Self { pub fn new(
name: &'static str,
cmp_map: OwnedRefMut<'a, AFLppCmpLogMap>,
add_meta: bool,
) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: None, size: None,
cmp_map: OwnedRefMut::Ref(map), cmp_map,
add_meta, add_meta,
original: false, original: false,
phantom: PhantomData, phantom: PhantomData,
@ -198,15 +202,15 @@ where
#[must_use] #[must_use]
pub fn with_size( pub fn with_size(
name: &'static str, name: &'static str,
map: &'a mut AFLppCmpLogMap, cmp_map: OwnedRefMut<'a, AFLppCmpLogMap>,
add_meta: bool, add_meta: bool,
original: bool, original: bool,
size: &'a mut usize, size: OwnedRefMut<'a, usize>,
) -> Self { ) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
size: Some(OwnedRefMut::Ref(size)), size: Some(size),
cmp_map: OwnedRefMut::Ref(map), cmp_map,
add_meta, add_meta,
original, original,
phantom: PhantomData, phantom: PhantomData,