From a976c3b6f53b6ce4a82c2117481e0b2a97ab774d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 10 May 2021 09:38:01 +0200 Subject: [PATCH] cmp observer --- libafl/src/observers/cmp.rs | 245 +++--------------------------------- libafl_targets/Cargo.toml | 4 +- 2 files changed, 16 insertions(+), 233 deletions(-) diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 29fa3b79d3..581908d202 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -4,251 +4,36 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +use core::slice::from_raw_parts_mut; +use serde::{Deserialize, Serialize}; use crate::{ - bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice}, + bolts::{ + ownedref::{OwnedRefMut, OwnedSliceMut}, + tuples::Named, + }, executors::HasExecHooks, observers::Observer, - state::HasMetadata, Error, }; -#[derive(Debug, Serialize, Deserialize)] -pub enum CmpValues { - U8((u8, u8)), - U16((u16, u16)), - U32((u32, u32)), - U64((u64, u64)), - Bytes((Vec, Vec)), -} +/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information +pub trait CmpObserver: Observer { + /// Get the number of usable cmps (all by default) + fn usable_count(&self) -> usize; -impl CmpValues { - #[must_use] - pub fn is_numeric(&self) -> bool { - matches!( - self, - CmpValues::U8(_) | CmpValues::U16(_) | CmpValues::U32(_) | CmpValues::U64(_) - ) - } - - #[must_use] - pub fn to_u64_tuple(&self) -> Option<(u64, u64)> { - match self { - CmpValues::U8(t) => Some((u64::from(t.0), u64::from(t.1))), - CmpValues::U16(t) => Some((u64::from(t.0), u64::from(t.1))), - CmpValues::U32(t) => Some((u64::from(t.0), u64::from(t.1))), - CmpValues::U64(t) => Some(*t), - _ => None, - } - } -} - -/// A state metadata holding a list of values logged from comparisons -#[derive(Default, Serialize, Deserialize)] -pub struct CmpValuesMetadata { - /// A `list` of values. - pub list: Vec, -} - -crate::impl_serdeany!(CmpValuesMetadata); - -impl AsSlice for CmpValuesMetadata { - /// Convert to a slice - #[must_use] - fn as_slice(&self) -> &[CmpValues] { - self.list.as_slice() - } -} - -impl CmpValuesMetadata { - /// Creates a new [`struct@CmpValuesMetadata`] - #[must_use] - pub fn new() -> Self { - Self { list: vec![] } - } -} - -/// A [`CmpMap`] traces comparisons during the current execution -pub trait CmpMap: Serialize + DeserializeOwned { /// Get the number of cmps fn len(&self) -> usize; - /// Get if it is empty - #[must_use] - fn is_empty(&self) -> bool { - self.len() == 0 - } + fn executions_for(idx: usize) -> usize; - // Get the number of executions for a cmp - fn executions_for(&self, idx: usize) -> usize; + fn kind_for(idx: usize) -> CmpKind; - // Get the number of logged executions for a cmp - fn usable_executions_for(&self, idx: usize) -> usize; + fn bytes_for(idx: usize) -> usize; - // Get the logged values for a cmp - fn values_of(&self, idx: usize, execution: usize) -> CmpValues; + fn values_of(idx: usize, execution: usize) -> (T, T); /// Reset the state fn reset(&mut self) -> Result<(), Error>; } - -/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`] -pub trait CmpObserver: Observer -where - CM: CmpMap, -{ - /// Get the number of usable cmps (all by default) - fn usable_count(&self) -> usize; - - /// Get the `CmpMap` - fn map(&self) -> &CM; - - /// Get the `CmpMap` (mut) - fn map_mut(&mut self) -> &mut CM; - - /// Add [`CmpValuesMetadata`] to the State including the logged values. - /// This routine does a basic loop filtering because loop index cmps are not interesting. - fn add_cmpvalues_meta(&mut self, state: &mut S) - where - S: HasMetadata, - { - if state.metadata().get::().is_none() { - state.add_metadata(CmpValuesMetadata::new()); - } - let meta = state.metadata_mut().get_mut::().unwrap(); - meta.list.clear(); - let count = self.usable_count(); - for i in 0..count { - let execs = self.map().usable_executions_for(i); - if execs > 0 { - // Recongize loops and discard if needed - if execs > 4 { - let mut increasing_v0 = 0; - let mut increasing_v1 = 0; - let mut decreasing_v0 = 0; - let mut decreasing_v1 = 0; - - let mut last: Option = None; - for j in 0..execs { - let val = self.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 { - increasing_v0 += 1; - } - if l.1.wrapping_add(1) == v.1 { - increasing_v1 += 1; - } - if l.0.wrapping_sub(1) == v.0 { - decreasing_v0 += 1; - } - if l.1.wrapping_sub(1) == v.1 { - decreasing_v1 += 1; - } - } - } - last = Some(val); - } - // We check for execs-2 because the logged execs may wrap and have something like - // 8 9 10 3 4 5 6 7 - if increasing_v0 >= execs - 2 - || increasing_v1 >= execs - 2 - || decreasing_v0 >= execs - 2 - || decreasing_v1 >= execs - 2 - { - continue; - } - } - for j in 0..execs { - meta.list.push(self.map().values_of(i, j)); - } - } - } - } -} - -/// 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>, - name: String, -} - -impl<'a, CM> CmpObserver 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 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 [`StdCmpObserver`] with the given name and map. - #[must_use] - pub fn new(name: &'static str, map: &'a mut CM) -> Self { - Self { - name: name.to_string(), - size: None, - map: OwnedRefMut::Ref(map), - } - } - - /// Creates a new [`StdCmpObserver`] with the given name, map and reference to variable size. - #[must_use] - pub fn with_size(name: &'static str, map: &'a mut CM, size: &'a mut usize) -> Self { - Self { - name: name.to_string(), - size: Some(OwnedRefMut::Ref(size)), - map: OwnedRefMut::Ref(map), - } - } -} diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index c4fdd07e3a..1749f10274 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -23,6 +23,4 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] rangemap = "0.1.10" -libafl = { path = "../libafl", version = "0.3.2", features = [] } -serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib -serde-big-array = "0.3.2" +libafl = { path = "../libafl", version = "0.2.1", features = [] }