cmp observer and feedback

This commit is contained in:
Andrea Fioraldi 2021-05-19 23:57:00 +02:00 committed by Omree
parent f81a52e14d
commit 8437c4adb7
5 changed files with 165 additions and 46 deletions

View File

@ -21,7 +21,6 @@ where
{ {
primary: A, primary: A,
secondary: B, secondary: B,
exec_tmout: Duration,
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
@ -80,7 +79,7 @@ where
} }
} }
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for TimeoutExecutor<A, B, I> impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for CombinedExecutor<A, B, I>
where where
A: Executor<I> + HasObservers<OT>, A: Executor<I> + HasObservers<OT>,
B: Executor<I>, B: Executor<I>,
@ -89,9 +88,9 @@ where
{ {
} }
impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for TimeoutExecutor<A, B, I> impl<A, B, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CombinedExecutor<A, B, I>
where where
A: Executor<I> + HasObservers<OT>, A: Executor<I> + HasExecHooks<EM, I, S, Z>,
B: Executor<I>, B: Executor<I>,
I: Input, I: Input,
{ {

View File

@ -1,18 +1,14 @@
use alloc::{ use alloc::string::{String, ToString};
string::{String, ToString},
};
use core::marker::PhantomData; use core::marker::PhantomData;
use num::Integer;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::tuples::Named, bolts::{tuples::Named, AsSlice},
executors::ExitKind, executors::ExitKind,
feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple}, feedbacks::Feedback,
inputs::Input, inputs::Input,
observers::{CmpObserver, ObserversTuple}, observers::{CmpMap, CmpObserver, CmpValues, ObserversTuple},
state::{HasFeedbackStates, HasMetadata}, state::HasMetadata,
utils::AsSlice,
Error, Error,
}; };
@ -20,15 +16,15 @@ use crate::{
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CmpValuesMetadata { pub struct CmpValuesMetadata {
/// A `list` of values. /// A `list` of values.
pub list: Vec<(u64, u64)>, pub list: Vec<CmpValues>,
} }
crate::impl_serdeany!(CmpValuesMetadata); crate::impl_serdeany!(CmpValuesMetadata);
impl AsSlice<(u64, u64)> for CmpValuesMetadata { impl AsSlice<CmpValues> for CmpValuesMetadata {
/// Convert to a slice /// Convert to a slice
#[must_use] #[must_use]
fn as_slice(&self) -> &[(u64, u64)] { fn as_slice(&self) -> &[CmpValues] {
self.list.as_slice() self.list.as_slice()
} }
} }
@ -36,24 +32,31 @@ impl AsSlice<(u64, u64)> for CmpValuesMetadata {
impl CmpValuesMetadata { impl CmpValuesMetadata {
/// Creates a new [`struct@CmpValuesMetadata`] /// Creates a new [`struct@CmpValuesMetadata`]
#[must_use] #[must_use]
pub fn new(list: Vec<(u64, u64)>) -> Self { pub fn new() -> Self {
Self { list } Self { list: vec![] }
} }
} }
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct CmpFeedback<T> { pub struct CmpFeedback<CM, CO>
where
CO: CmpObserver<CM>,
CM: CmpMap,
{
name: String, name: String,
phantom: PhantomData<T> phantom: PhantomData<(CM, CO)>,
} }
impl<I, S, T> Feedback<I, S> for CmpFeedback<T> impl<CM, CO, I, S> Feedback<I, S> for CmpFeedback<CM, CO>
where where
I: Input, I: Input,
CO: CmpObserver<CM>,
CM: CmpMap,
S: HasMetadata,
{ {
fn is_interesting<OT>( fn is_interesting<OT>(
&mut self, &mut self,
_state: &mut S, state: &mut S,
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
@ -61,36 +64,59 @@ where
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
if state.metadata().get::<CmpValuesMetadata>().is_none() {
state.add_metadata(CmpValuesMetadata::new());
}
let meta = state.metadata_mut().get_mut::<CmpValuesMetadata>().unwrap();
meta.list.clear();
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<CmpObserver<T>>(self.name()).unwrap(); let observer = observers.match_name::<CO>(self.name()).unwrap();
// TODO let count = observer.usable_count();
for i in 0..count {
let execs = observer.map().usable_executions_for(i);
if execs > 0 {
// Recongize loops and discard
// TODO
for j in 0..execs {
meta.list.push(observer.map().values_of(i, j));
}
}
}
Ok(false) Ok(false)
} }
} }
impl Named for CmpFeedback { impl<CM, CO> Named for CmpFeedback<CM, CO>
where
CO: CmpObserver<CM>,
CM: CmpMap,
{
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
self.name.as_str() self.name.as_str()
} }
} }
impl CmpFeedback { impl<CM, CO> CmpFeedback<CM, CO>
where
CO: CmpObserver<CM>,
CM: CmpMap,
{
/// Creates a new [`CmpFeedback`] /// Creates a new [`CmpFeedback`]
#[must_use] #[must_use]
pub fn new(name: &'static str) -> Self { pub fn with_name(name: &'static str) -> Self {
Self { Self {
name: name.to_string(), name: name.to_string(),
phantom: PhantomData phantom: PhantomData,
} }
} }
/// Creates a new [`CmpFeedback`] /// Creates a new [`CmpFeedback`]
#[must_use] #[must_use]
pub fn new_with_observer(observer: &CmpObserver<T>) -> Self { pub fn new(observer: &CO) -> Self {
Self { Self {
name: observer.name().to_string(), name: observer.name().to_string(),
phantom: PhantomData phantom: PhantomData,
} }
} }
} }

View File

@ -4,6 +4,9 @@
pub mod map; pub mod map;
pub use map::*; pub use map::*;
pub mod cmp;
pub use cmp::*;
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@ -5,34 +5,125 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use core::slice::from_raw_parts_mut; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ bolts::{ownedref::OwnedRefMut, tuples::Named},
ownedref::{OwnedRefMut, OwnedSliceMut},
tuples::Named,
},
executors::HasExecHooks, executors::HasExecHooks,
observers::Observer, observers::Observer,
Error, Error,
}; };
/// A [`CmpObserver`] observes the traced comparisons during the current execution #[derive(Serialize, Deserialize)]
pub trait CmpObserver<T>: Observer { pub enum CmpValues {
/// Get the number of usable cmps (all by default) U8((u8, u8)),
fn usable_count(&self) -> usize; U16((u16, u16)),
U32((u32, u32)),
U64((u64, u64)),
Bytes((Vec<u8>, Vec<u8>)),
}
/// A [`CmpMap`] traces comparisons during the current execution
pub trait CmpMap: Serialize + DeserializeOwned {
/// Get the number of cmps /// Get the number of cmps
fn len(&self) -> usize; fn len(&self) -> usize;
fn executions_for(idx: usize) -> usize; fn executions_for(&self, idx: usize) -> usize;
fn bytes_for(idx: usize) -> usize; fn usable_executions_for(&self, idx: usize) -> usize;
fn values_of(idx: usize, execution: usize) -> (T, T); fn values_of(&self, idx: usize, execution: usize) -> CmpValues;
/// Reset the state /// Reset the state
fn reset(&mut self) -> Result<(), Error>; fn reset(&mut self) -> Result<(), Error>;
} }
/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`]
pub trait CmpObserver<CM>: Observer
where
CM: CmpMap,
{
/// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize;
fn map(&self) -> &CM;
fn map_mut(&mut self) -> &mut CM;
}
/// A standard [`CmpObserver`] observer
#[derive(Serialize, Deserialize, Debug)]
#[serde(bound = "CM: serde::de::DeserializeOwned")]
pub struct StdCmpObserver<'a, CM>
where
CM: CmpMap,
{
map: OwnedRefMut<'a, CM>,
size: Option<OwnedRefMut<'a, usize>>,
name: String,
}
impl<'a, CM> CmpObserver<CM> for StdCmpObserver<'a, CM>
where
CM: CmpMap,
{
/// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize {
match &self.size {
None => self.map().len(),
Some(o) => *o.as_ref(),
}
}
fn map(&self) -> &CM {
self.map.as_ref()
}
fn map_mut(&mut self) -> &mut CM {
self.map.as_mut()
}
}
impl<'a, CM> Observer for StdCmpObserver<'a, CM> where CM: CmpMap {}
impl<'a, CM, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for StdCmpObserver<'a, CM>
where
CM: CmpMap,
{
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.map.as_mut().reset()?;
Ok(())
}
}
impl<'a, CM> Named for StdCmpObserver<'a, CM>
where
CM: CmpMap,
{
fn name(&self) -> &str {
&self.name
}
}
impl<'a, CM> StdCmpObserver<'a, CM>
where
CM: CmpMap,
{
/// Creates a new [`CmpObserver`] with the given name.
#[must_use]
pub fn new(name: &'static str, map: &'a mut CM) -> Self {
Self {
name: name.to_string(),
size: None,
map: OwnedRefMut::Ref(map),
}
}
// TODO with_size
}

View File

@ -25,4 +25,4 @@ cc = { version = "1.0", features = ["parallel"] }
[dependencies] [dependencies]
rangemap = "0.1.10" rangemap = "0.1.10"
libafl = { path = "../libafl", version = "0.2.1", features = [] } libafl = { path = "../libafl", version = "0.3", features = [] }