diff --git a/afl/src/feedbacks/mod.rs b/afl/src/feedbacks/mod.rs index b7f2fd4e7b..8206a73f5d 100644 --- a/afl/src/feedbacks/mod.rs +++ b/afl/src/feedbacks/mod.rs @@ -189,7 +189,7 @@ where let mut interesting = 0; // TODO optimize let observer = observers.match_name_type::(&self.name).unwrap(); - let size = observer.map().len(); + let size = observer.usable_count(); for i in 0..size { let history = self.history_map[i]; let item = observer.map()[i]; diff --git a/afl/src/observers/mod.rs b/afl/src/observers/mod.rs index adeae619c8..c57643dc0f 100644 --- a/afl/src/observers/mod.rs +++ b/afl/src/observers/mod.rs @@ -2,7 +2,7 @@ extern crate num; use serde::{Deserialize, Serialize}; -use crate::serde_anymap::ArrayMut; +use crate::serde_anymap::{Cptr, ArrayMut}; use crate::tuples::{MatchNameAndType, MatchType, Named, TupleList}; use crate::AflError; @@ -92,6 +92,11 @@ where /// Get the map (mutable) fn map_mut(&mut self) -> &mut [T]; + /// Get the number of usable entries in the map (all by default) + fn usable_count(&self) -> usize { + self.map().len() + } + /// Get the initial value for reset() fn initial(&self) -> T; @@ -106,7 +111,8 @@ where fn reset_map(&mut self) -> Result<(), AflError> { // Normal memset, see https://rust.godbolt.org/z/Trs5hv let initial = self.initial(); - for i in self.map_mut().iter_mut() { + let cnt = self.usable_count(); + for i in self.map_mut()[0..cnt].iter_mut() { *i = initial; } Ok(()) @@ -204,6 +210,102 @@ where } } +#[derive(Serialize, Deserialize)] +#[serde(bound = "T: serde::de::DeserializeOwned")] +pub struct VariableMapObserver +where + T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + map: ArrayMut, + size: Cptr, + initial: T, + name: String, +} + +impl Observer for VariableMapObserver +where + T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn reset(&mut self) -> Result<(), AflError> { + self.reset_map() + } +} + +impl Named for VariableMapObserver +where + T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn name(&self) -> &str { + self.name.as_str() + } +} + +impl MapObserver for VariableMapObserver +where + T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + #[inline] + fn map(&self) -> &[T] { + self.map.as_slice() + } + + #[inline] + fn map_mut(&mut self) -> &mut [T] { + self.map.as_mut_slice() + } + + #[inline] + fn usable_count(&self) -> usize { + *self.size.as_ref() + } + + #[inline] + fn initial(&self) -> T { + self.initial + } + + #[inline] + fn initial_mut(&mut self) -> &mut T { + &mut self.initial + } + + #[inline] + fn set_initial(&mut self, initial: T) { + self.initial = initial + } +} + +impl VariableMapObserver +where + T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, +{ + /// Creates a new MapObserver + pub fn new(name: &'static str, map: &'static mut [T], size: &usize) -> Self { + let initial = if map.len() > 0 { map[0] } else { T::default() }; + Self { + map: ArrayMut::Cptr((map.as_mut_ptr(), map.len())), + size: Cptr::Cptr(size as *const _), + name: name.into(), + initial, + } + } + + /// Creates a new MapObserver from a raw pointer + pub fn new_from_ptr(name: &'static str, map_ptr: *mut T, max_len: usize, size_ptr: *const usize) -> Self { + unsafe { + let initial = if max_len > 0 { *map_ptr } else { T::default() }; + VariableMapObserver { + map: ArrayMut::Cptr((map_ptr, max_len)), + size: Cptr::Cptr(size_ptr), + name: name.into(), + initial, + } + } + } +} + /* #[cfg(feature = "std")] #[cfg(test)] diff --git a/afl/src/serde_anymap.rs b/afl/src/serde_anymap.rs index 4cab18cb85..d5993b8c7a 100644 --- a/afl/src/serde_anymap.rs +++ b/afl/src/serde_anymap.rs @@ -629,7 +629,84 @@ impl<'a, T: Sized> SliceMut<'a, T> { } } -pub enum Array { +pub enum Cptr { + Cptr(*const T), + Owned(Box), +} + +impl serde::Serialize for Cptr { + fn serialize(&self, se: S) -> Result + where + S: serde::Serializer, + { + self.as_ref().serialize(se) + } +} + +impl<'de, T: Sized + serde::de::DeserializeOwned> Deserialize<'de> for Cptr +where + Vec: Deserialize<'de>, +{ + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(de).map(Cptr::Owned) + } +} + +impl Cptr { + pub fn as_ref(&self) -> &T { + match self { + Cptr::Cptr(p) => unsafe { p.as_ref().unwrap() }, + Cptr::Owned(v) => v.as_ref(), + } + } +} + +pub enum CptrMut { + Cptr(*mut T), + Owned(Box), +} + +impl serde::Serialize for CptrMut { + fn serialize(&self, se: S) -> Result + where + S: serde::Serializer, + { + self.as_ref().serialize(se) + } +} + +impl<'de, T: Sized + serde::de::DeserializeOwned> Deserialize<'de> for CptrMut +where + Vec: Deserialize<'de>, +{ + fn deserialize(de: D) -> Result + where + D: serde::Deserializer<'de>, + { + Deserialize::deserialize(de).map(CptrMut::Owned) + } +} + +impl CptrMut { + pub fn as_ref(&self) -> &T { + match self { + CptrMut::Cptr(p) => unsafe { p.as_ref().unwrap() }, + CptrMut::Owned(b) => b.as_ref(), + } + } + + pub fn as_mut(&mut self) -> &mut T { + match self { + CptrMut::Cptr(p) => unsafe { p.as_mut().unwrap() }, + CptrMut::Owned(b) => b.as_mut(), + } + } +} + +pub enum Array { Cptr((*const T, usize)), Owned(Vec), } @@ -655,7 +732,7 @@ where } } -impl Array { +impl Array { pub fn as_slice(&self) -> &[T] { match self { Array::Cptr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) }, @@ -664,7 +741,7 @@ impl Array { } } -pub enum ArrayMut { +pub enum ArrayMut { Cptr((*mut T, usize)), Owned(Vec), } @@ -690,7 +767,7 @@ where } } -impl ArrayMut { +impl ArrayMut { pub fn as_slice(&self) -> &[T] { match self { ArrayMut::Cptr(p) => unsafe { core::slice::from_raw_parts(p.0, p.1) }, diff --git a/fuzzers/qemufuzzer/src/lib.rs b/fuzzers/qemufuzzer/src/lib.rs index 38f83b434a..7454f25d3b 100644 --- a/fuzzers/qemufuzzer/src/lib.rs +++ b/fuzzers/qemufuzzer/src/lib.rs @@ -14,7 +14,7 @@ use afl::feedbacks::MaxMapFeedback; use afl::generators::RandPrintablesGenerator; use afl::mutators::scheduled::HavocBytesMutator; use afl::mutators::HasMaxSize; -use afl::observers::StdMapObserver; +use afl::observers::VariableMapObserver; use afl::stages::mutational::StdMutationalStage; use afl::tuples::tuple_list; use afl::utils::StdRand; @@ -66,7 +66,7 @@ pub extern "C" fn fuzz_main_loop() { } println!("We're a client, let's fuzz :)"); - let edges_observer = StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { fuzz_hitcounts_map.as_mut_ptr() }, unsafe { fuzz_edges_id }); + let edges_observer = VariableMapObserver::new(&NAME_COV_MAP, unsafe { &mut fuzz_hitcounts_map }, unsafe { &fuzz_edges_id }); let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer); let executor = InMemoryExecutor::new("QEMUFuzzer", harness, tuple_list!(edges_observer));