From eba6646f90b17a9da08dc0eaf86b6634a99adf21 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 7 May 2021 16:11:45 +0200 Subject: [PATCH 01/43] libafl_targets: refactor sancov trace-pc --- libafl_targets/Cargo.toml | 4 +--- libafl_targets/src/cmplog.h | 4 +++- libafl_targets/src/lib.rs | 3 --- libafl_targets/src/sancov_cmp.c | 36 ++++++++++----------------------- 4 files changed, 15 insertions(+), 32 deletions(-) diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index c1f4eb9ded..c4fdd07e3a 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -13,11 +13,9 @@ edition = "2018" [features] default = [] libfuzzer = [] -sancov_pcguard_edges = [] -sancov_pcguard_hitcounts = [] sancov_value_profile = [] sancov_cmplog = [] -sancov_pcguard = ["sancov_pcguard_hitcounts"] +pcguard = ["pcguard_hitcounts"] clippy = [] # Ignore compiler warnings during clippy [build-dependencies] diff --git a/libafl_targets/src/cmplog.h b/libafl_targets/src/cmplog.h index 762ed548d3..5ada7ddf84 100644 --- a/libafl_targets/src/cmplog.h +++ b/libafl_targets/src/cmplog.h @@ -29,7 +29,9 @@ extern CmpLogMap libafl_cmplog_map; extern uint8_t libafl_cmplog_enabled; -static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { + +void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { + if (!libafl_cmplog_enabled) return; diff --git a/libafl_targets/src/lib.rs b/libafl_targets/src/lib.rs index 4d9130ab0c..6420630534 100644 --- a/libafl_targets/src/lib.rs +++ b/libafl_targets/src/lib.rs @@ -13,9 +13,6 @@ pub mod libfuzzer; #[cfg(feature = "libfuzzer")] pub use libfuzzer::*; -pub mod coverage; -pub use coverage::*; - pub mod value_profile; pub use value_profile::*; diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 1066557a61..8cc560f054 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -1,12 +1,6 @@ #include "common.h" - -#ifdef SANCOV_VALUE_PROFILE #include "value_profile.h" -#endif - -#ifdef SANCOV_CMPLOG #include "cmplog.h" -#endif #if defined(__APPLE__) #pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1 @@ -35,12 +29,10 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; + +#ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile1(k, arg1, arg2); #endif -#ifdef SANCOV_CMPLOG - k &= CMPLOG_MAP_W - 1; - __libafl_targets_cmplog(k, 1, (uint64_t)arg1, (uint64_t)arg2); -#endif } @@ -51,12 +43,10 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) { #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; + +#ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile2(k, arg1, arg2); #endif -#ifdef SANCOV_CMPLOG - k &= CMPLOG_MAP_W - 1; - __libafl_targets_cmplog(k, 2, (uint64_t)arg1, (uint64_t)arg2); -#endif } @@ -67,12 +57,10 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; + +#ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile4(k, arg1, arg2); #endif -#ifdef SANCOV_CMPLOG - k &= CMPLOG_MAP_W - 1; - __libafl_targets_cmplog(k, 4, (uint64_t)arg1, (uint64_t)arg2); -#endif } @@ -90,21 +78,23 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { __libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2); #endif +#ifdef SANCOV_VALUE_PROFILE + __libafl_targets_value_profile8(k, arg1, arg2); +#endif + } void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { uintptr_t rt = RETADDR; - // if (!cases[1]) return; - for (uint64_t i = 0; i < cases[0]; i++) { uintptr_t k = rt + i; k = (k >> 4) ^ (k << 8); + k &= MAP_SIZE - 1; // val , cases[i + 2] #ifdef SANCOV_VALUE_PROFILE - k &= MAP_SIZE - 1; switch (cases[1]) { case 8: __libafl_targets_value_profile1(k, (uint8_t)val, (uint8_t)cases[i + 2]); @@ -120,10 +110,6 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { break; } #endif -#ifdef SANCOV_CMPLOG - k &= CMPLOG_MAP_W - 1; - __libafl_targets_cmplog(k, cases[1] / 8, val, cases[i + 2]); -#endif } From a976c3b6f53b6ce4a82c2117481e0b2a97ab774d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Mon, 10 May 2021 09:38:01 +0200 Subject: [PATCH 02/43] 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 = [] } From f25554805d4418cec4afbb7684057f883b6993ea Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 14 May 2021 15:57:12 +0200 Subject: [PATCH 03/43] libaf_targets: new structure to isolate sancov --- fuzzers/libfuzzer_stb_image/Cargo.toml | 3 ++- libafl_targets/Cargo.toml | 4 +++- libafl_targets/src/cmplog.h | 2 +- libafl_targets/src/lib.rs | 6 +++--- libafl_targets/src/sancov_cmp.c | 18 ++++++++++++++++++ libafl_targets/src/sancov_pcguard.rs | 2 +- 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index ea49909a65..d7ef610490 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -17,7 +17,8 @@ debug = true [dependencies] libafl = { path = "../../libafl/" } -libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "sancov_cmplog", "libfuzzer"] } + +libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "libfuzzer"] } [build-dependencies] cc = { version = "1.0", features = ["parallel"] } diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index 1749f10274..071977e0f2 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -13,9 +13,11 @@ edition = "2018" [features] default = [] libfuzzer = [] +sancov_pcguard_edges = [] +sancov_pcguard_hitcounts = [] sancov_value_profile = [] sancov_cmplog = [] -pcguard = ["pcguard_hitcounts"] +sancov_pcguard = ["sancov_pcguard_hitcounts"] clippy = [] # Ignore compiler warnings during clippy [build-dependencies] diff --git a/libafl_targets/src/cmplog.h b/libafl_targets/src/cmplog.h index 5ada7ddf84..b595033602 100644 --- a/libafl_targets/src/cmplog.h +++ b/libafl_targets/src/cmplog.h @@ -30,7 +30,7 @@ extern CmpLogMap libafl_cmplog_map; extern uint8_t libafl_cmplog_enabled; -void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { +static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { if (!libafl_cmplog_enabled) return; diff --git a/libafl_targets/src/lib.rs b/libafl_targets/src/lib.rs index 6420630534..38b3945b18 100644 --- a/libafl_targets/src/lib.rs +++ b/libafl_targets/src/lib.rs @@ -1,8 +1,5 @@ //! `libafl_targets` contains runtime code, injected in the target itself during compilation. -#[macro_use] -extern crate serde_big_array; - #[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] pub mod sancov_pcguard; #[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] @@ -13,6 +10,9 @@ pub mod libfuzzer; #[cfg(feature = "libfuzzer")] pub use libfuzzer::*; +pub mod coverage; +pub use coverage::*; + pub mod value_profile; pub use value_profile::*; diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 8cc560f054..643aa9fd5f 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -33,6 +33,9 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { #ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile1(k, arg1, arg2); #endif +#ifdef SANCOV_CMPLOG + __libafl_targets_cmplog(k, 1, (uint64_t)arg1, (uint64_t)arg2); +#endif } @@ -47,6 +50,9 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) { #ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile2(k, arg1, arg2); #endif +#ifdef SANCOV_CMPLOG + __libafl_targets_cmplog(k, 2, (uint64_t)arg1, (uint64_t)arg2); +#endif } @@ -61,6 +67,9 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { #ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile4(k, arg1, arg2); #endif +#ifdef SANCOV_CMPLOG + __libafl_targets_cmplog(k, 4, (uint64_t)arg1, (uint64_t)arg2); +#endif } @@ -81,6 +90,9 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { #ifdef SANCOV_VALUE_PROFILE __libafl_targets_value_profile8(k, arg1, arg2); #endif +#ifdef SANCOV_CMPLOG + __libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2); +#endif } @@ -88,6 +100,8 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { uintptr_t rt = RETADDR; + // if (!cases[1]) return; + for (uint64_t i = 0; i < cases[0]; i++) { uintptr_t k = rt + i; @@ -110,6 +124,10 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { break; } #endif +#ifdef SANCOV_CMPLOG + __libafl_targets_cmplog(k, cases[1] / 8, val, cases[i + 2]); +#endif + } diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 6d5f6dcc19..4c4ffecf7e 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -1,6 +1,6 @@ //! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`. -use crate::coverage::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM}; +use crate::coverage::*; #[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] #[cfg(not(any(doc, feature = "clippy")))] From a3a2b47b2a7cc4731e5c7a3a2a8e828057435afb Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Fri, 14 May 2021 15:58:54 +0200 Subject: [PATCH 04/43] fix C warning --- libafl_targets/src/sancov_cmp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 643aa9fd5f..440f06c4b5 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -1,6 +1,12 @@ #include "common.h" + +#ifdef SANCOV_VALUE_PROFILE #include "value_profile.h" +#endif + +#ifdef SANCOV_CMPLOG #include "cmplog.h" +#endif #if defined(__APPLE__) #pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1 From f81a52e14d1f39c1fb1cf20d3ec055609bd43858 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Sun, 16 May 2021 22:59:22 +0200 Subject: [PATCH 05/43] combined executor --- libafl/src/executors/combined.rs | 87 ++++++++++++++++++++++------- libafl/src/executors/mod.rs | 2 + libafl/src/feedbacks/cmp.rs | 96 ++++++++++++++++++++++++++++++++ libafl/src/observers/cmp.rs | 5 +- 4 files changed, 167 insertions(+), 23 deletions(-) create mode 100644 libafl/src/feedbacks/cmp.rs diff --git a/libafl/src/executors/combined.rs b/libafl/src/executors/combined.rs index a4ae7b3ccb..535a63377b 100644 --- a/libafl/src/executors/combined.rs +++ b/libafl/src/executors/combined.rs @@ -1,22 +1,43 @@ //! A `CombinedExecutor` wraps a primary executor and a secondary one +use core::marker::PhantomData; + use crate::{ - executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, + executors::{ + Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks, + }, inputs::Input, observers::ObserversTuple, Error, }; /// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one -pub struct CombinedExecutor { + +pub struct CombinedExecutor +where + A: Executor, + B: Executor, + I: Input, +{ primary: A, secondary: B, + exec_tmout: Duration, + phantom: PhantomData, } -impl CombinedExecutor { +impl CombinedExecutor +where + A: Executor, + B: Executor, + I: Input, +{ /// Create a new `CombinedExecutor`, wrapping the given `executor`s. - pub fn new(primary: A, secondary: B) -> Self { - Self { primary, secondary } + pub fn new(primary: A, secondary: B) -> Self { + Self { + primary, + secondary, + phantom: PhantomData, + } } /// Retrieve the primary `Executor` that is wrapped by this `CombinedExecutor`. @@ -30,26 +51,22 @@ impl CombinedExecutor { } } -impl Executor for CombinedExecutor +impl Executor for CombinedExecutor where - A: Executor, - B: Executor, + A: Executor, + B: Executor, I: Input, { - fn run_target( - &mut self, - fuzzer: &mut Z, - state: &mut S, - mgr: &mut EM, - input: &I, - ) -> Result { - self.primary.run_target(fuzzer, state, mgr, input) + fn run_target(&mut self, input: &I) -> Result { + self.primary.run_target(input) } } -impl HasObservers for CombinedExecutor +impl HasObservers for CombinedExecutor where - A: HasObservers, + A: Executor + HasObservers, + B: Executor, + I: Input, OT: ObserversTuple, { #[inline] @@ -63,10 +80,40 @@ where } } -impl HasObserversHooks for CombinedExecutor +impl HasObserversHooks for TimeoutExecutor where - A: HasObservers, + A: Executor + HasObservers, + B: Executor, I: Input, OT: ObserversTuple + HasExecHooksTuple, { } + +impl HasExecHooks for TimeoutExecutor +where + A: Executor + HasObservers, + B: Executor, + I: Input, +{ + #[inline] + fn pre_exec( + &mut self, + fuzzer: &mut Z, + state: &mut S, + mgr: &mut EM, + input: &I, + ) -> Result<(), Error> { + self.primary.pre_exec(fuzzer, state, mgr, input) + } + + #[inline] + fn post_exec( + &mut self, + fuzzer: &mut Z, + state: &mut S, + mgr: &mut EM, + input: &I, + ) -> Result<(), Error> { + self.primary.post_exec(fuzzer, state, mgr, input) + } +} diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 25bcaf3c89..2b992f74da 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -4,6 +4,8 @@ pub mod inprocess; pub use inprocess::InProcessExecutor; pub mod timeout; pub use timeout::TimeoutExecutor; +pub mod combined; +pub use combined::CombinedExecutor; #[cfg(all(feature = "std", unix))] pub mod forkserver; diff --git a/libafl/src/feedbacks/cmp.rs b/libafl/src/feedbacks/cmp.rs new file mode 100644 index 0000000000..1617d204bd --- /dev/null +++ b/libafl/src/feedbacks/cmp.rs @@ -0,0 +1,96 @@ +use alloc::{ + string::{String, ToString}, +}; +use core::marker::PhantomData; +use num::Integer; +use serde::{Deserialize, Serialize}; + +use crate::{ + bolts::tuples::Named, + executors::ExitKind, + feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple}, + inputs::Input, + observers::{CmpObserver, ObserversTuple}, + state::{HasFeedbackStates, HasMetadata}, + utils::AsSlice, + Error, +}; + +/// A state metadata holding a list of values logged from comparisons +#[derive(Serialize, Deserialize)] +pub struct CmpValuesMetadata { + /// A `list` of values. + pub list: Vec<(u64, u64)>, +} + +crate::impl_serdeany!(CmpValuesMetadata); + +impl AsSlice<(u64, u64)> for CmpValuesMetadata { + /// Convert to a slice + #[must_use] + fn as_slice(&self) -> &[(u64, u64)] { + self.list.as_slice() + } +} + +impl CmpValuesMetadata { + /// Creates a new [`struct@CmpValuesMetadata`] + #[must_use] + pub fn new(list: Vec<(u64, u64)>) -> Self { + Self { list } + } +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct CmpFeedback { + name: String, + phantom: PhantomData +} + +impl Feedback for CmpFeedback +where + I: Input, +{ + fn is_interesting( + &mut self, + _state: &mut S, + _input: &I, + observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + OT: ObserversTuple, + { + // TODO Replace with match_name_type when stable + let observer = observers.match_name::>(self.name()).unwrap(); + // TODO + Ok(false) + } +} + +impl Named for CmpFeedback { + #[inline] + fn name(&self) -> &str { + self.name.as_str() + } +} + +impl CmpFeedback { + /// Creates a new [`CmpFeedback`] + #[must_use] + pub fn new(name: &'static str) -> Self { + Self { + name: name.to_string(), + phantom: PhantomData + } + } + + /// Creates a new [`CmpFeedback`] + #[must_use] + pub fn new_with_observer(observer: &CmpObserver) -> Self { + Self { + name: observer.name().to_string(), + phantom: PhantomData + } + } +} diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 581908d202..b375ff93a8 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -6,6 +6,7 @@ use alloc::{ }; use core::slice::from_raw_parts_mut; +use num_enum::{IntoPrimitive, TryFromPrimitive}; use serde::{Deserialize, Serialize}; use crate::{ @@ -18,7 +19,7 @@ use crate::{ Error, }; -/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information +/// A [`CmpObserver`] observes the traced comparisons during the current execution pub trait CmpObserver: Observer { /// Get the number of usable cmps (all by default) fn usable_count(&self) -> usize; @@ -28,8 +29,6 @@ pub trait CmpObserver: Observer { fn executions_for(idx: usize) -> usize; - fn kind_for(idx: usize) -> CmpKind; - fn bytes_for(idx: usize) -> usize; fn values_of(idx: usize, execution: usize) -> (T, T); From 8437c4adb7da06eff0502841e160a11662eabce7 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 19 May 2021 23:57:00 +0200 Subject: [PATCH 06/43] cmp observer and feedback --- libafl/src/executors/combined.rs | 7 +- libafl/src/feedbacks/cmp.rs | 80 ++++++++++++++------- libafl/src/feedbacks/mod.rs | 3 + libafl/src/observers/cmp.rs | 119 +++++++++++++++++++++++++++---- libafl_targets/Cargo.toml | 2 +- 5 files changed, 165 insertions(+), 46 deletions(-) diff --git a/libafl/src/executors/combined.rs b/libafl/src/executors/combined.rs index 535a63377b..9d208e8bac 100644 --- a/libafl/src/executors/combined.rs +++ b/libafl/src/executors/combined.rs @@ -21,7 +21,6 @@ where { primary: A, secondary: B, - exec_tmout: Duration, phantom: PhantomData, } @@ -80,7 +79,7 @@ where } } -impl HasObserversHooks for TimeoutExecutor +impl HasObserversHooks for CombinedExecutor where A: Executor + HasObservers, B: Executor, @@ -89,9 +88,9 @@ where { } -impl HasExecHooks for TimeoutExecutor +impl HasExecHooks for CombinedExecutor where - A: Executor + HasObservers, + A: Executor + HasExecHooks, B: Executor, I: Input, { diff --git a/libafl/src/feedbacks/cmp.rs b/libafl/src/feedbacks/cmp.rs index 1617d204bd..dd51c058c7 100644 --- a/libafl/src/feedbacks/cmp.rs +++ b/libafl/src/feedbacks/cmp.rs @@ -1,18 +1,14 @@ -use alloc::{ - string::{String, ToString}, -}; +use alloc::string::{String, ToString}; use core::marker::PhantomData; -use num::Integer; use serde::{Deserialize, Serialize}; use crate::{ - bolts::tuples::Named, + bolts::{tuples::Named, AsSlice}, executors::ExitKind, - feedbacks::{Feedback, FeedbackState, FeedbackStatesTuple}, + feedbacks::Feedback, inputs::Input, - observers::{CmpObserver, ObserversTuple}, - state::{HasFeedbackStates, HasMetadata}, - utils::AsSlice, + observers::{CmpMap, CmpObserver, CmpValues, ObserversTuple}, + state::HasMetadata, Error, }; @@ -20,15 +16,15 @@ use crate::{ #[derive(Serialize, Deserialize)] pub struct CmpValuesMetadata { /// A `list` of values. - pub list: Vec<(u64, u64)>, + pub list: Vec, } - + crate::impl_serdeany!(CmpValuesMetadata); -impl AsSlice<(u64, u64)> for CmpValuesMetadata { +impl AsSlice for CmpValuesMetadata { /// Convert to a slice #[must_use] - fn as_slice(&self) -> &[(u64, u64)] { + fn as_slice(&self) -> &[CmpValues] { self.list.as_slice() } } @@ -36,24 +32,31 @@ impl AsSlice<(u64, u64)> for CmpValuesMetadata { impl CmpValuesMetadata { /// Creates a new [`struct@CmpValuesMetadata`] #[must_use] - pub fn new(list: Vec<(u64, u64)>) -> Self { - Self { list } + pub fn new() -> Self { + Self { list: vec![] } } } #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct CmpFeedback { +pub struct CmpFeedback +where + CO: CmpObserver, + CM: CmpMap, +{ name: String, - phantom: PhantomData + phantom: PhantomData<(CM, CO)>, } -impl Feedback for CmpFeedback +impl Feedback for CmpFeedback where I: Input, + CO: CmpObserver, + CM: CmpMap, + S: HasMetadata, { fn is_interesting( &mut self, - _state: &mut S, + state: &mut S, _input: &I, observers: &OT, _exit_kind: &ExitKind, @@ -61,36 +64,59 @@ where where OT: ObserversTuple, { + if state.metadata().get::().is_none() { + state.add_metadata(CmpValuesMetadata::new()); + } + let meta = state.metadata_mut().get_mut::().unwrap(); + meta.list.clear(); // TODO Replace with match_name_type when stable - let observer = observers.match_name::>(self.name()).unwrap(); - // TODO + let observer = observers.match_name::(self.name()).unwrap(); + 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) } } -impl Named for CmpFeedback { +impl Named for CmpFeedback +where + CO: CmpObserver, + CM: CmpMap, +{ #[inline] fn name(&self) -> &str { self.name.as_str() } } -impl CmpFeedback { +impl CmpFeedback +where + CO: CmpObserver, + CM: CmpMap, +{ /// Creates a new [`CmpFeedback`] #[must_use] - pub fn new(name: &'static str) -> Self { + pub fn with_name(name: &'static str) -> Self { Self { name: name.to_string(), - phantom: PhantomData + phantom: PhantomData, } } /// Creates a new [`CmpFeedback`] #[must_use] - pub fn new_with_observer(observer: &CmpObserver) -> Self { + pub fn new(observer: &CO) -> Self { Self { name: observer.name().to_string(), - phantom: PhantomData + phantom: PhantomData, } } } diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index b7e001b8f0..ce3c2390c0 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -4,6 +4,9 @@ pub mod map; pub use map::*; +pub mod cmp; +pub use cmp::*; + use alloc::string::{String, ToString}; use serde::{Deserialize, Serialize}; diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index b375ff93a8..3fbd4b7681 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -5,34 +5,125 @@ use alloc::{ vec::Vec, }; -use core::slice::from_raw_parts_mut; -use num_enum::{IntoPrimitive, TryFromPrimitive}; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - bolts::{ - ownedref::{OwnedRefMut, OwnedSliceMut}, - tuples::Named, - }, + bolts::{ownedref::OwnedRefMut, tuples::Named}, executors::HasExecHooks, observers::Observer, Error, }; -/// A [`CmpObserver`] observes the traced comparisons during the current execution -pub trait CmpObserver: Observer { - /// Get the number of usable cmps (all by default) - fn usable_count(&self) -> usize; +#[derive(Serialize, Deserialize)] +pub enum CmpValues { + U8((u8, u8)), + U16((u16, u16)), + U32((u32, u32)), + U64((u64, u64)), + Bytes((Vec, Vec)), +} +/// A [`CmpMap`] traces comparisons during the current execution +pub trait CmpMap: Serialize + DeserializeOwned { /// Get the number of cmps 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 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; + + 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>, + 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 [`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 +} diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index 071977e0f2..c73ceb2deb 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -25,4 +25,4 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] rangemap = "0.1.10" -libafl = { path = "../libafl", version = "0.2.1", features = [] } +libafl = { path = "../libafl", version = "0.3", features = [] } From ae5b4f88cc0ed3166e68b3238ed20d272765b2f7 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 00:29:16 +0200 Subject: [PATCH 07/43] I2SRandReplace mutator --- libafl/src/mutators/token_mutations.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 5223155a8e..f2f1733b7f 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -15,9 +15,10 @@ use std::{ use crate::{ bolts::rands::Rand, + feedbacks::cmp::CmpValuesMetadata, inputs::{HasBytesVec, Input}, mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named}, - observers::cmp::{CmpValues, CmpValuesMetadata}, + observers::cmp::CmpValues, state::{HasMaxSize, HasMetadata, HasRand}, Error, }; @@ -310,7 +311,6 @@ where S: HasMetadata + HasRand + HasMaxSize, R: Rand, { - #[allow(clippy::too_many_lines)] fn mutate( &mut self, state: &mut S, @@ -344,13 +344,13 @@ where let mut result = MutationResult::Skipped; match cmp_values { CmpValues::U8(v) => { - for byte in bytes.iter_mut().take(len).skip(off) { - if *byte == v.0 { - *byte = v.1; + for i in off..len { + if bytes[i] == v.0 { + bytes[i] = v.1; result = MutationResult::Mutated; break; - } else if *byte == v.1 { - *byte = v.0; + } else if bytes[i] == v.1 { + bytes[i] = v.0; result = MutationResult::Mutated; break; } @@ -449,8 +449,6 @@ where } } - //println!("{:?}", result); - Ok(result) } } From ccfc95aa3a2e42b90003a9da60deb08724e9ea18 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 00:57:51 +0200 Subject: [PATCH 08/43] impl CmpMap for CmpLogMap in libafl_targets --- libafl_targets/Cargo.toml | 2 ++ libafl_targets/src/cmplog.rs | 6 +----- libafl_targets/src/lib.rs | 3 +++ 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index c73ceb2deb..f965aaf748 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -26,3 +26,5 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] rangemap = "0.1.10" libafl = { path = "../libafl", version = "0.3", features = [] } +serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib +serde-big-array = "0.3.2" diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index 77b7e2671c..f74d91ae7c 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -2,13 +2,9 @@ //! The values will then be used in subsequent mutations. use libafl::{ - bolts::{ownedref::OwnedRefMut, tuples::Named}, - executors::HasExecHooks, - observers::{CmpMap, CmpObserver, CmpValues, Observer}, - state::HasMetadata, + observers::{CmpMap, CmpValues}, Error, }; - use serde::{Deserialize, Serialize}; // TODO compile time flag diff --git a/libafl_targets/src/lib.rs b/libafl_targets/src/lib.rs index 38b3945b18..4d9130ab0c 100644 --- a/libafl_targets/src/lib.rs +++ b/libafl_targets/src/lib.rs @@ -1,5 +1,8 @@ //! `libafl_targets` contains runtime code, injected in the target itself during compilation. +#[macro_use] +extern crate serde_big_array; + #[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] pub mod sancov_pcguard; #[cfg(any(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] From 933b65dd862f3ec2788ece3a7a5fca4d401e5a4a Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 01:25:01 +0200 Subject: [PATCH 09/43] cmplog observer --- fuzzers/libfuzzer_stb_image/Cargo.toml | 3 +- fuzzers/libfuzzer_stb_image/src/main.rs | 7 +- libafl/src/bolts/tuples.rs | 15 +- libafl/src/observers/cmp.rs | 2 +- libafl/src/stages/tracing.rs | 179 ++++++++++++++++-------- libafl_targets/src/cmplog.rs | 22 ++- libafl_targets/src/sancov_cmp.c | 23 ++- 7 files changed, 160 insertions(+), 91 deletions(-) diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index d7ef610490..ea49909a65 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -17,8 +17,7 @@ debug = true [dependencies] libafl = { path = "../../libafl/" } - -libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "libfuzzer"] } +libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "sancov_cmplog", "libfuzzer"] } [build-dependencies] cc = { version = "1.0", features = ["parallel"] } diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index c718b1ad2e..14256237a9 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -12,11 +12,11 @@ use libafl::{ events::setup_restarting_mgr_std, executors::{inprocess::InProcessExecutor, ExitKind}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CmpFeedback, CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, - mutators::token_mutations::I2SRandReplace, + mutators::token_mutations::{I2SRandReplace, Tokens}, observers::{StdMapObserver, TimeObserver}, stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, StdState}, @@ -72,6 +72,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); + let cmplog = unsafe { &mut CMPLOG_MAP }; + let cmplog_observer = CmpLogObserver::new("cmplog", cmplog); + let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); diff --git a/libafl/src/bolts/tuples.rs b/libafl/src/bolts/tuples.rs index e9ae0f0c83..8f9ab3d289 100644 --- a/libafl/src/bolts/tuples.rs +++ b/libafl/src/bolts/tuples.rs @@ -361,9 +361,12 @@ where } /// Merge two `TupeList` -pub trait Merge { +pub trait Merge: TupleList +where + T: TupleList, +{ /// The Resulting [`TupleList`], of an [`Merge::merge()`] call - type MergeResult; + type MergeResult: TupleList; /// Merge and return the merged tuple #[must_use] @@ -371,7 +374,10 @@ pub trait Merge { } /// Implement merge for an empty tuple list. -impl Merge for () { +impl Merge for () +where + T: TupleList, +{ type MergeResult = T; fn merge(self, value: T) -> Self::MergeResult { @@ -382,7 +388,10 @@ impl Merge for () { /// Implement merge for non-empty tuple list. impl Merge for (Head, Tail) where + T: TupleList, + Self: TupleList, Tail: Merge, + (Head, Tail::MergeResult): TupleList, { type MergeResult = (Head, Tail::MergeResult); diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 3fbd4b7681..61e84944a6 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -115,7 +115,7 @@ impl<'a, CM> StdCmpObserver<'a, CM> where CM: CmpMap, { - /// Creates a new [`CmpObserver`] with the given name. + /// Creates a new [`StdCmpObserver`] with the given name. #[must_use] pub fn new(name: &'static str, map: &'a mut CM) -> Self { Self { diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 4e37dce554..5e9801ded7 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -1,96 +1,163 @@ -use core::{marker::PhantomData, mem::drop}; +use core::marker::PhantomData; use crate::{ + bolts::rands::Rand, corpus::Corpus, - executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks}, + fuzzer::Evaluator, inputs::Input, mark_feature_time, - observers::ObserversTuple, + mutators::Mutator, stages::Stage, start_timer, - state::{HasClientPerfStats, HasCorpus, HasExecutions}, + state::{HasClientPerfStats, HasCorpus, HasRand}, Error, }; #[cfg(feature = "introspection")] use crate::stats::PerfFeature; -/// The default mutational stage -#[derive(Clone, Debug)] -pub struct TracingStage +// TODO multi mutators stage + +/// A Mutational stage is the stage in a fuzzing run that mutates inputs. +/// Mutational stages will usually have a range of mutations that are +/// being applied to the input one by one, between executions. +pub trait TracingStage: Stage where - I: Input, C: Corpus, - TE: Executor + HasObservers + HasObserversHooks, - OT: ObserversTuple + HasExecHooksTuple, - S: HasClientPerfStats + HasExecutions + HasCorpus, + M: Mutator, + I: Input, + S: HasClientPerfStats + HasCorpus, + Z: Evaluator, { - tracer_executor: TE, - #[allow(clippy::type_complexity)] - phantom: PhantomData<(C, EM, I, OT, S, TE, Z)>, + /// The mutator registered for this stage + fn mutator(&self) -> &M; + + /// The mutator registered for this stage (mutable) + fn mutator_mut(&mut self) -> &mut M; + + /// Gets the number of iterations this mutator should run for. + fn iterations(&self, state: &mut S) -> usize; + + /// Runs this (mutational) stage for the given testcase + #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... + fn perform_mutational( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), Error> { + let num = self.iterations(state); + + for i in 0..num { + start_timer!(state); + let mut input = state + .corpus() + .get(corpus_idx)? + .borrow_mut() + .load_input()? + .clone(); + mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + + start_timer!(state); + self.mutator_mut().mutate(state, &mut input, i as i32)?; + mark_feature_time!(state, PerfFeature::Mutate); + + // Time is measured directly the `evaluate_input` function + let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; + + start_timer!(state); + self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; + mark_feature_time!(state, PerfFeature::MutatePostExec); + } + Ok(()) + } } -impl Stage for TracingStage +/// Default value, how many iterations each stage gets, as an upper bound +/// It may randomly continue earlier. +pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; + +/// The default mutational stage +#[derive(Clone, Debug)] +pub struct StdMutationalStage where - I: Input, C: Corpus, - TE: Executor + HasObservers + HasObserversHooks, - OT: ObserversTuple + HasExecHooksTuple, - S: HasClientPerfStats + HasExecutions + HasCorpus, + M: Mutator, + I: Input, + R: Rand, + S: HasClientPerfStats + HasCorpus + HasRand, + Z: Evaluator, +{ + mutator: M, + #[allow(clippy::type_complexity)] + phantom: PhantomData<(C, E, EM, I, R, S, Z)>, +} + +impl MutationalStage + for StdMutationalStage +where + C: Corpus, + M: Mutator, + I: Input, + R: Rand, + S: HasClientPerfStats + HasCorpus + HasRand, + Z: Evaluator, +{ + /// The mutator, added to this stage + #[inline] + fn mutator(&self) -> &M { + &self.mutator + } + + /// The list of mutators, added to this stage (as mutable ref) + #[inline] + fn mutator_mut(&mut self) -> &mut M { + &mut self.mutator + } + + /// Gets the number of iterations as a random number + fn iterations(&self, state: &mut S) -> usize { + 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize + } +} + +impl Stage for StdMutationalStage +where + C: Corpus, + M: Mutator, + I: Input, + R: Rand, + S: HasClientPerfStats + HasCorpus + HasRand, + Z: Evaluator, { #[inline] fn perform( &mut self, fuzzer: &mut Z, - _executor: &mut E, + executor: &mut E, state: &mut S, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { - start_timer!(state); - let input = state - .corpus() - .get(corpus_idx)? - .borrow_mut() - .load_input()? - .clone(); - mark_feature_time!(state, PerfFeature::GetInputFromCorpus); - - start_timer!(state); - self.tracer_executor - .pre_exec_observers(fuzzer, state, manager, &input)?; - mark_feature_time!(state, PerfFeature::PreExecObservers); - - start_timer!(state); - drop( - self.tracer_executor - .run_target(fuzzer, state, manager, &input)?, - ); - mark_feature_time!(state, PerfFeature::TargetExecution); - - *state.executions_mut() += 1; - - start_timer!(state); - self.tracer_executor - .post_exec_observers(fuzzer, state, manager, &input)?; - mark_feature_time!(state, PerfFeature::PostExecObservers); - - Ok(()) + self.perform_mutational(fuzzer, executor, state, manager, corpus_idx) } } -impl TracingStage +impl StdMutationalStage where - I: Input, C: Corpus, - TE: Executor + HasObservers + HasObserversHooks, - OT: ObserversTuple + HasExecHooksTuple, - S: HasClientPerfStats + HasExecutions + HasCorpus, + M: Mutator, + I: Input, + R: Rand, + S: HasClientPerfStats + HasCorpus + HasRand, + Z: Evaluator, { /// Creates a new default mutational stage - pub fn new(tracer_executor: TE) -> Self { + pub fn new(mutator: M) -> Self { Self { - tracer_executor, + mutator, phantom: PhantomData, } } diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index f74d91ae7c..182ea2539c 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -2,9 +2,12 @@ //! The values will then be used in subsequent mutations. use libafl::{ - observers::{CmpMap, CmpValues}, + bolts::{ownedref::OwnedRefMut, tuples::Named}, + executors::HasExecHooks, + observers::{CmpMap, CmpObserver, CmpValues, Observer}, Error, }; + use serde::{Deserialize, Serialize}; // TODO compile time flag @@ -140,12 +143,11 @@ pub static mut libafl_cmplog_enabled: u8 = 0; pub use libafl_cmplog_enabled as CMPLOG_ENABLED; -/// A [`CmpObserver`] observer for `CmpLog` +/// A [`CmpObserver`] observer for CmpLog #[derive(Serialize, Deserialize, Debug)] pub struct CmpLogObserver<'a> { map: OwnedRefMut<'a, CmpLogMap>, size: Option>, - add_meta: bool, name: String, } @@ -169,10 +171,7 @@ impl<'a> CmpObserver for CmpLogObserver<'a> { impl<'a> Observer for CmpLogObserver<'a> {} -impl<'a, EM, I, S, Z> HasExecHooks for CmpLogObserver<'a> -where - S: HasMetadata, -{ +impl<'a, EM, I, S, Z> HasExecHooks for CmpLogObserver<'a> { fn pre_exec( &mut self, _fuzzer: &mut Z, @@ -190,16 +189,13 @@ where fn post_exec( &mut self, _fuzzer: &mut Z, - state: &mut S, + _state: &mut S, _mgr: &mut EM, _input: &I, ) -> Result<(), Error> { unsafe { CMPLOG_ENABLED = 0; } - if self.add_meta { - self.add_cmpvalues_meta(state); - } Ok(()) } } @@ -213,11 +209,11 @@ impl<'a> Named for CmpLogObserver<'a> { impl<'a> CmpLogObserver<'a> { /// Creates a new [`CmpLogObserver`] with the given name. #[must_use] - pub fn new(name: &'static str, map: &'a mut CmpLogMap, add_meta: bool) -> Self { + pub fn new(name: &'static str, map: &'a mut CmpLogMap) -> Self { Self { name: name.to_string(), size: None, - add_meta, + map: OwnedRefMut::Ref(map), } } diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 440f06c4b5..de795b4e45 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -33,13 +33,13 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); -#ifdef SANCOV_VALUE_PROFILE - k &= MAP_SIZE - 1; #ifdef SANCOV_VALUE_PROFILE + k &= MAP_SIZE - 1; __libafl_targets_value_profile1(k, arg1, arg2); #endif #ifdef SANCOV_CMPLOG + k &= CMPLOG_MAP_W - 1; __libafl_targets_cmplog(k, 1, (uint64_t)arg1, (uint64_t)arg2); #endif @@ -50,13 +50,13 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); -#ifdef SANCOV_VALUE_PROFILE - k &= MAP_SIZE - 1; #ifdef SANCOV_VALUE_PROFILE + k &= MAP_SIZE - 1; __libafl_targets_value_profile2(k, arg1, arg2); #endif #ifdef SANCOV_CMPLOG + k &= CMPLOG_MAP_W - 1; __libafl_targets_cmplog(k, 2, (uint64_t)arg1, (uint64_t)arg2); #endif @@ -67,13 +67,13 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); -#ifdef SANCOV_VALUE_PROFILE - k &= MAP_SIZE - 1; #ifdef SANCOV_VALUE_PROFILE + k &= MAP_SIZE - 1; __libafl_targets_value_profile4(k, arg1, arg2); #endif #ifdef SANCOV_CMPLOG + k &= CMPLOG_MAP_W - 1; __libafl_targets_cmplog(k, 4, (uint64_t)arg1, (uint64_t)arg2); #endif @@ -84,6 +84,7 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); + #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; __libafl_targets_value_profile8(k, arg1, arg2); @@ -93,13 +94,6 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { __libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2); #endif -#ifdef SANCOV_VALUE_PROFILE - __libafl_targets_value_profile8(k, arg1, arg2); -#endif -#ifdef SANCOV_CMPLOG - __libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2); -#endif - } void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { @@ -112,9 +106,9 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { uintptr_t k = rt + i; k = (k >> 4) ^ (k << 8); - k &= MAP_SIZE - 1; // val , cases[i + 2] #ifdef SANCOV_VALUE_PROFILE + k &= MAP_SIZE - 1; switch (cases[1]) { case 8: __libafl_targets_value_profile1(k, (uint8_t)val, (uint8_t)cases[i + 2]); @@ -131,6 +125,7 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { } #endif #ifdef SANCOV_CMPLOG + k &= CMPLOG_MAP_W - 1; __libafl_targets_cmplog(k, cases[1] / 8, val, cases[i + 2]); #endif From b28306519f7952b4647a06e34677534718a19c0a Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Thu, 20 May 2021 05:23:22 +0200 Subject: [PATCH 10/43] clippy --- libafl/src/stages/tracing.rs | 39 ++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 5e9801ded7..25c654780d 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -1,4 +1,4 @@ -use core::marker::PhantomData; +use core::{marker::PhantomData, mem::drop}; use crate::{ bolts::rands::Rand, @@ -141,7 +141,42 @@ where manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { - self.perform_mutational(fuzzer, executor, state, manager, corpus_idx) + start_timer!(state); + let input = state + .corpus() + .get(corpus_idx)? + .borrow_mut() + .load_input()? + .clone(); + mark_feature_time!(state, PerfFeature::GetInputFromCorpus); + + start_timer!(state); + self.tracer_executor + .pre_exec_observers(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PreExecObservers); + + start_timer!(state); + self.tracer_executor + .pre_exec(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PreExec); + + start_timer!(state); + drop(self.tracer_executor.run_target(&input)?); + mark_feature_time!(state, PerfFeature::TargetExecution); + + start_timer!(state); + self.tracer_executor + .post_exec(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PostExec); + + *state.executions_mut() += 1; + + start_timer!(state); + self.tracer_executor + .post_exec_observers(fuzzer, state, manager, &input)?; + mark_feature_time!(state, PerfFeature::PostExecObservers); + + Ok(()) } } From f61140bdcface5b484f1ad8aa81bb1f1bb34209a Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 08:54:03 +0200 Subject: [PATCH 11/43] TracingStage --- libafl/src/stages/tracing.rs | 150 ++++++++--------------------------- 1 file changed, 32 insertions(+), 118 deletions(-) diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 25c654780d..0ba71f6259 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -1,142 +1,54 @@ use core::{marker::PhantomData, mem::drop}; use crate::{ - bolts::rands::Rand, corpus::Corpus, - fuzzer::Evaluator, + executors::{Executor, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks}, inputs::Input, mark_feature_time, - mutators::Mutator, + observers::ObserversTuple, stages::Stage, start_timer, - state::{HasClientPerfStats, HasCorpus, HasRand}, + state::{HasClientPerfStats, HasCorpus, HasExecutions}, Error, }; #[cfg(feature = "introspection")] use crate::stats::PerfFeature; -// TODO multi mutators stage - -/// A Mutational stage is the stage in a fuzzing run that mutates inputs. -/// Mutational stages will usually have a range of mutations that are -/// being applied to the input one by one, between executions. -pub trait TracingStage: Stage -where - C: Corpus, - M: Mutator, - I: Input, - S: HasClientPerfStats + HasCorpus, - Z: Evaluator, -{ - /// The mutator registered for this stage - fn mutator(&self) -> &M; - - /// The mutator registered for this stage (mutable) - fn mutator_mut(&mut self) -> &mut M; - - /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut S) -> usize; - - /// Runs this (mutational) stage for the given testcase - #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... - fn perform_mutational( - &mut self, - fuzzer: &mut Z, - executor: &mut E, - state: &mut S, - manager: &mut EM, - corpus_idx: usize, - ) -> Result<(), Error> { - let num = self.iterations(state); - - for i in 0..num { - start_timer!(state); - let mut input = state - .corpus() - .get(corpus_idx)? - .borrow_mut() - .load_input()? - .clone(); - mark_feature_time!(state, PerfFeature::GetInputFromCorpus); - - start_timer!(state); - self.mutator_mut().mutate(state, &mut input, i as i32)?; - mark_feature_time!(state, PerfFeature::Mutate); - - // Time is measured directly the `evaluate_input` function - let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?; - - start_timer!(state); - self.mutator_mut().post_exec(state, i as i32, corpus_idx)?; - mark_feature_time!(state, PerfFeature::MutatePostExec); - } - Ok(()) - } -} - -/// Default value, how many iterations each stage gets, as an upper bound -/// It may randomly continue earlier. -pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; - /// The default mutational stage #[derive(Clone, Debug)] -pub struct StdMutationalStage +pub struct TracingStage where - C: Corpus, - M: Mutator, I: Input, - R: Rand, - S: HasClientPerfStats + HasCorpus + HasRand, - Z: Evaluator, + C: Corpus, + TE: Executor + + HasObservers + + HasExecHooks + + HasObserversHooks, + OT: ObserversTuple + HasExecHooksTuple, + S: HasClientPerfStats + HasExecutions + HasCorpus, { - mutator: M, + tracer_executor: TE, #[allow(clippy::type_complexity)] - phantom: PhantomData<(C, E, EM, I, R, S, Z)>, + phantom: PhantomData<(C, EM, I, OT, S, TE, Z)>, } -impl MutationalStage - for StdMutationalStage +impl Stage for TracingStage where - C: Corpus, - M: Mutator, I: Input, - R: Rand, - S: HasClientPerfStats + HasCorpus + HasRand, - Z: Evaluator, -{ - /// The mutator, added to this stage - #[inline] - fn mutator(&self) -> &M { - &self.mutator - } - - /// The list of mutators, added to this stage (as mutable ref) - #[inline] - fn mutator_mut(&mut self) -> &mut M { - &mut self.mutator - } - - /// Gets the number of iterations as a random number - fn iterations(&self, state: &mut S) -> usize { - 1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize - } -} - -impl Stage for StdMutationalStage -where C: Corpus, - M: Mutator, - I: Input, - R: Rand, - S: HasClientPerfStats + HasCorpus + HasRand, - Z: Evaluator, + TE: Executor + + HasObservers + + HasExecHooks + + HasObserversHooks, + OT: ObserversTuple + HasExecHooksTuple, + S: HasClientPerfStats + HasExecutions + HasCorpus, { #[inline] fn perform( &mut self, fuzzer: &mut Z, - executor: &mut E, + _executor: &mut E, state: &mut S, manager: &mut EM, corpus_idx: usize, @@ -161,7 +73,7 @@ where mark_feature_time!(state, PerfFeature::PreExec); start_timer!(state); - drop(self.tracer_executor.run_target(&input)?); + let _ = self.tracer_executor.run_target(&input)?; mark_feature_time!(state, PerfFeature::TargetExecution); start_timer!(state); @@ -180,19 +92,21 @@ where } } -impl StdMutationalStage +impl TracingStage where - C: Corpus, - M: Mutator, I: Input, - R: Rand, - S: HasClientPerfStats + HasCorpus + HasRand, - Z: Evaluator, + C: Corpus, + TE: Executor + + HasObservers + + HasExecHooks + + HasObserversHooks, + OT: ObserversTuple + HasExecHooksTuple, + S: HasClientPerfStats + HasExecutions + HasCorpus, { /// Creates a new default mutational stage - pub fn new(mutator: M) -> Self { + pub fn new(tracer_executor: TE) -> Self { Self { - mutator, + tracer_executor, phantom: PhantomData, } } From 16d4c36f12cc754a4e26586330a359f6cee19c4e Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 11:49:28 +0200 Subject: [PATCH 12/43] working random cmplog mutations --- fuzzers/libfuzzer_stb_image/src/main.rs | 18 ++-- libafl/src/bolts/tuples.rs | 15 +-- libafl/src/feedbacks/cmp.rs | 122 ------------------------ libafl/src/feedbacks/mod.rs | 3 - libafl/src/mutators/token_mutations.rs | 5 +- libafl/src/observers/cmp.rs | 110 ++++++++++++++++++++- libafl_targets/src/cmplog.rs | 16 +++- 7 files changed, 136 insertions(+), 153 deletions(-) delete mode 100644 libafl/src/feedbacks/cmp.rs diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index 14256237a9..b7a144ebe7 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -12,15 +12,15 @@ use libafl::{ events::setup_restarting_mgr_std, executors::{inprocess::InProcessExecutor, ExitKind}, feedback_or, - feedbacks::{CmpFeedback, CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, - mutators::token_mutations::{I2SRandReplace, Tokens}, + mutators::token_mutations::I2SRandReplace, observers::{StdMapObserver, TimeObserver}, stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, StdState}, - stats::MultiStats, + stats::SimpleStats, Error, }; @@ -73,7 +73,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let time_observer = TimeObserver::new("time"); let cmplog = unsafe { &mut CMPLOG_MAP }; - let cmplog_observer = CmpLogObserver::new("cmplog", cmplog); + let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); @@ -155,9 +155,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re } // Secondary harness due to mut ownership - let mut harness = |input: &BytesInput| { - let target = input.target_bytes(); - let buf = target.as_slice(); + let mut harness = |buf: &[u8]| { libfuzzer_test_one_input(buf); ExitKind::Ok }; @@ -172,14 +170,16 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re )?); // Setup a randomic Input2State stage - let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); + + //let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); // Setup a basic mutator let mutator = StdScheduledMutator::new(havoc_mutations()); let mutational = StdMutationalStage::new(mutator); // The order of the stages matter! - let mut stages = tuple_list!(tracing, i2s, mutational); + + let mut stages = tuple_list!(tracing, mutational); fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?; diff --git a/libafl/src/bolts/tuples.rs b/libafl/src/bolts/tuples.rs index 8f9ab3d289..e9ae0f0c83 100644 --- a/libafl/src/bolts/tuples.rs +++ b/libafl/src/bolts/tuples.rs @@ -361,12 +361,9 @@ where } /// Merge two `TupeList` -pub trait Merge: TupleList -where - T: TupleList, -{ +pub trait Merge { /// The Resulting [`TupleList`], of an [`Merge::merge()`] call - type MergeResult: TupleList; + type MergeResult; /// Merge and return the merged tuple #[must_use] @@ -374,10 +371,7 @@ where } /// Implement merge for an empty tuple list. -impl Merge for () -where - T: TupleList, -{ +impl Merge for () { type MergeResult = T; fn merge(self, value: T) -> Self::MergeResult { @@ -388,10 +382,7 @@ where /// Implement merge for non-empty tuple list. impl Merge for (Head, Tail) where - T: TupleList, - Self: TupleList, Tail: Merge, - (Head, Tail::MergeResult): TupleList, { type MergeResult = (Head, Tail::MergeResult); diff --git a/libafl/src/feedbacks/cmp.rs b/libafl/src/feedbacks/cmp.rs deleted file mode 100644 index dd51c058c7..0000000000 --- a/libafl/src/feedbacks/cmp.rs +++ /dev/null @@ -1,122 +0,0 @@ -use alloc::string::{String, ToString}; -use core::marker::PhantomData; -use serde::{Deserialize, Serialize}; - -use crate::{ - bolts::{tuples::Named, AsSlice}, - executors::ExitKind, - feedbacks::Feedback, - inputs::Input, - observers::{CmpMap, CmpObserver, CmpValues, ObserversTuple}, - state::HasMetadata, - Error, -}; - -/// A state metadata holding a list of values logged from comparisons -#[derive(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![] } - } -} - -#[derive(Serialize, Deserialize, Clone, Debug)] -pub struct CmpFeedback -where - CO: CmpObserver, - CM: CmpMap, -{ - name: String, - phantom: PhantomData<(CM, CO)>, -} - -impl Feedback for CmpFeedback -where - I: Input, - CO: CmpObserver, - CM: CmpMap, - S: HasMetadata, -{ - fn is_interesting( - &mut self, - state: &mut S, - _input: &I, - observers: &OT, - _exit_kind: &ExitKind, - ) -> Result - where - OT: ObserversTuple, - { - if state.metadata().get::().is_none() { - state.add_metadata(CmpValuesMetadata::new()); - } - let meta = state.metadata_mut().get_mut::().unwrap(); - meta.list.clear(); - // TODO Replace with match_name_type when stable - let observer = observers.match_name::(self.name()).unwrap(); - 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) - } -} - -impl Named for CmpFeedback -where - CO: CmpObserver, - CM: CmpMap, -{ - #[inline] - fn name(&self) -> &str { - self.name.as_str() - } -} - -impl CmpFeedback -where - CO: CmpObserver, - CM: CmpMap, -{ - /// Creates a new [`CmpFeedback`] - #[must_use] - pub fn with_name(name: &'static str) -> Self { - Self { - name: name.to_string(), - phantom: PhantomData, - } - } - - /// Creates a new [`CmpFeedback`] - #[must_use] - pub fn new(observer: &CO) -> Self { - Self { - name: observer.name().to_string(), - phantom: PhantomData, - } - } -} diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index ce3c2390c0..b7e001b8f0 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -4,9 +4,6 @@ pub mod map; pub use map::*; -pub mod cmp; -pub use cmp::*; - use alloc::string::{String, ToString}; use serde::{Deserialize, Serialize}; diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index f2f1733b7f..c50e671c11 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -15,10 +15,9 @@ use std::{ use crate::{ bolts::rands::Rand, - feedbacks::cmp::CmpValuesMetadata, inputs::{HasBytesVec, Input}, mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named}, - observers::cmp::CmpValues, + observers::cmp::{CmpValues, CmpValuesMetadata}, state::{HasMaxSize, HasMetadata, HasRand}, Error, }; @@ -449,6 +448,8 @@ where } } + //println!("{:?}", result); + Ok(result) } } diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 61e84944a6..4f0cd4c18d 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -8,13 +8,14 @@ use alloc::{ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - bolts::{ownedref::OwnedRefMut, tuples::Named}, + bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice}, executors::HasExecHooks, observers::Observer, + state::HasMetadata, Error, }; -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub enum CmpValues { U8((u8, u8)), U16((u16, u16)), @@ -23,6 +24,53 @@ pub enum CmpValues { Bytes((Vec, Vec)), } +impl CmpValues { + pub fn is_numeric(&self) -> bool { + match self { + CmpValues::U8(_) => true, + CmpValues::U16(_) => true, + CmpValues::U32(_) => true, + CmpValues::U64(_) => true, + _ => false, + } + } + + pub fn to_u64_tuple(&self) -> Option<(u64, u64)> { + match self { + CmpValues::U8(t) => Some((t.0 as u64, t.1 as u64)), + CmpValues::U16(t) => Some((t.0 as u64, t.1 as u64)), + CmpValues::U32(t) => Some((t.0 as u64, t.1 as u64)), + CmpValues::U64(t) => Some((t.0 as u64, t.1 as u64)), + _ => None, + } + } +} + +/// A state metadata holding a list of values logged from comparisons +#[derive(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 @@ -49,6 +97,64 @@ where fn map(&self) -> &CM; fn map_mut(&mut self) -> &mut CM; + + 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 diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index 182ea2539c..e217bfb7ce 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -5,6 +5,7 @@ use libafl::{ bolts::{ownedref::OwnedRefMut, tuples::Named}, executors::HasExecHooks, observers::{CmpMap, CmpObserver, CmpValues, Observer}, + state::HasMetadata, Error, }; @@ -148,6 +149,7 @@ pub use libafl_cmplog_enabled as CMPLOG_ENABLED; pub struct CmpLogObserver<'a> { map: OwnedRefMut<'a, CmpLogMap>, size: Option>, + add_meta: bool, name: String, } @@ -171,7 +173,10 @@ impl<'a> CmpObserver for CmpLogObserver<'a> { impl<'a> Observer for CmpLogObserver<'a> {} -impl<'a, EM, I, S, Z> HasExecHooks for CmpLogObserver<'a> { +impl<'a, EM, I, S, Z> HasExecHooks for CmpLogObserver<'a> +where + S: HasMetadata, +{ fn pre_exec( &mut self, _fuzzer: &mut Z, @@ -189,13 +194,17 @@ impl<'a, EM, I, S, Z> HasExecHooks for CmpLogObserver<'a> { fn post_exec( &mut self, _fuzzer: &mut Z, - _state: &mut S, + state: &mut S, _mgr: &mut EM, _input: &I, ) -> Result<(), Error> { unsafe { CMPLOG_ENABLED = 0; } + + if self.add_meta { + self.add_cmpvalues_meta(state); + } Ok(()) } } @@ -209,11 +218,12 @@ impl<'a> Named for CmpLogObserver<'a> { impl<'a> CmpLogObserver<'a> { /// Creates a new [`CmpLogObserver`] with the given name. #[must_use] - pub fn new(name: &'static str, map: &'a mut CmpLogMap) -> Self { + pub fn new(name: &'static str, map: &'a mut CmpLogMap, add_meta: bool) -> Self { Self { name: name.to_string(), size: None, + add_meta, map: OwnedRefMut::Ref(map), } } From aa6df29a9cc8450aab386e42a031a9b161e5872e Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 11:53:13 +0200 Subject: [PATCH 13/43] enable cmplog for libfuzzer_stb_image --- fuzzers/libfuzzer_stb_image/src/main.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index b7a144ebe7..c3e3d6b88b 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -170,16 +170,14 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re )?); // Setup a randomic Input2State stage - - //let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); + let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); // Setup a basic mutator let mutator = StdScheduledMutator::new(havoc_mutations()); let mutational = StdMutationalStage::new(mutator); // The order of the stages matter! - - let mut stages = tuple_list!(tracing, mutational); + let mut stages = tuple_list!(tracing, i2s, mutational); fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?; From c4f13df9c719ea63a2f1e4026fee9c4129d0329d Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 11:59:15 +0200 Subject: [PATCH 14/43] re-enable new testcase stats print --- libafl/src/events/llmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 35dc577669..a5ac71fa15 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -170,7 +170,7 @@ where let client = stats.client_stats_mut_for(sender_id); client.update_corpus_size(*corpus_size as u64); client.update_executions(*executions as u64, *time); - stats.display(event.name().to_string(), sender_id); + stats.display(event.name().to_string() + " #" + &sender_id.to_string()); Ok(BrokerEventResult::Forward) } Event::UpdateStats { From aa14c903dba0dbf0da33d1e5a5329a64a748ae18 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 12:01:32 +0200 Subject: [PATCH 15/43] fix update stats display --- libafl/src/events/llmp.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index a5ac71fa15..86ff0c984e 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -181,17 +181,7 @@ where // TODO: The stats buffer should be added on client add. let client = stats.client_stats_mut_for(sender_id); client.update_executions(*executions as u64, *time); - stats.display(event.name().to_string(), sender_id); - Ok(BrokerEventResult::Handled) - } - Event::UpdateUserStats { - name, - value, - phantom: _, - } => { - let client = stats.client_stats_mut_for(sender_id); - client.update_user_stats(name.clone(), value.clone()); - stats.display(event.name().to_string(), sender_id); + stats.display(event.name().to_string() + " #" + &sender_id.to_string()); Ok(BrokerEventResult::Handled) } #[cfg(feature = "introspection")] From 69d87b3763c4b6157dc177ec1796e9bb9883f66b Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 12:11:26 +0200 Subject: [PATCH 16/43] bump 0.3.1 --- fuzzers/baby_fuzzer/Cargo.toml | 2 +- fuzzers/frida_libpng/Cargo.toml | 2 +- fuzzers/libfuzzer_libmozjpeg/Cargo.toml | 2 +- fuzzers/libfuzzer_libmozjpeg/src/lib.rs | 1 - fuzzers/libfuzzer_libpng/Cargo.toml | 2 +- fuzzers/libfuzzer_libpng/src/lib.rs | 1 - fuzzers/libfuzzer_libpng_launcher/Cargo.toml | 2 +- fuzzers/libfuzzer_libpng_launcher/src/lib.rs | 1 - fuzzers/libfuzzer_reachability/Cargo.toml | 2 +- fuzzers/libfuzzer_stb_image/Cargo.toml | 2 +- libafl/Cargo.toml | 4 ++-- libafl_cc/Cargo.toml | 2 +- libafl_derive/Cargo.toml | 2 +- libafl_frida/Cargo.toml | 4 ++-- libafl_targets/Cargo.toml | 2 +- 15 files changed, 14 insertions(+), 17 deletions(-) diff --git a/fuzzers/baby_fuzzer/Cargo.toml b/fuzzers/baby_fuzzer/Cargo.toml index 1d8aedf13d..97fe602b1b 100644 --- a/fuzzers/baby_fuzzer/Cargo.toml +++ b/fuzzers/baby_fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index a68944cdaf..d2227e5837 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frida_libpng" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" build = "build.rs" diff --git a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml index 6137d50894..f166ef35fa 100644 --- a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml +++ b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libmozjpeg" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs index 7f68c7ed63..fb4782cf02 100644 --- a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs @@ -15,7 +15,6 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, - inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::StdMapObserver, diff --git a/fuzzers/libfuzzer_libpng/Cargo.toml b/fuzzers/libfuzzer_libpng/Cargo.toml index 5c38cd2133..39252a73a6 100644 --- a/fuzzers/libfuzzer_libpng/Cargo.toml +++ b/fuzzers/libfuzzer_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index 411768118b..ca1011ad7d 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -16,7 +16,6 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, - inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml index b8466488f2..289b80606c 100644 --- a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng_launcher" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs index 996ec170bb..9384e434da 100644 --- a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs @@ -24,7 +24,6 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, - inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libfuzzer_reachability/Cargo.toml b/fuzzers/libfuzzer_reachability/Cargo.toml index c04a484e59..044a57420a 100644 --- a/fuzzers/libfuzzer_reachability/Cargo.toml +++ b/fuzzers/libfuzzer_reachability/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_reachability" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index ea49909a65..8bdfb95cf8 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_stb_image" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" build = "build.rs" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 58f57ea890..a5d663fe1e 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] description = "Slot your own fuzzers together and extend their features using Rust" documentation = "https://docs.rs/libafl" @@ -52,7 +52,7 @@ path = "./examples/llmp_test/main.rs" required-features = ["std"] [dependencies] -libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.2" } +libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.1" } tuple_list = "0.1.2" hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible num = "0.4.0" diff --git a/libafl_cc/Cargo.toml b/libafl_cc/Cargo.toml index 302402bb0f..9500348ac7 100644 --- a/libafl_cc/Cargo.toml +++ b/libafl_cc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_cc" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi "] description = "Commodity library to wrap compilers and link LibAFL" documentation = "https://docs.rs/libafl_cc" diff --git a/libafl_derive/Cargo.toml b/libafl_derive/Cargo.toml index 36ef86f99f..878fd34d21 100644 --- a/libafl_derive/Cargo.toml +++ b/libafl_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_derive" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi "] description = "Derive proc-macro crate for LibAFL" documentation = "https://docs.rs/libafl_derive" diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index 712f906017..86ef12dc73 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_frida" -version = "0.3.2" +version = "0.3.1" authors = ["s1341 "] description = "Frida backend library for LibAFL" documentation = "https://docs.rs/libafl_frida" @@ -15,7 +15,7 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] libafl = { path = "../libafl", version = "0.3.1", features = ["std", "libafl_derive"] } -libafl_targets = { path = "../libafl_targets", version = "0.3.2" } +libafl_targets = { path = "../libafl_targets", version = "0.3.1" } nix = "0.20.0" libc = "0.2.92" hashbrown = "0.11" diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index f965aaf748..d053891581 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_targets" -version = "0.3.2" +version = "0.3.1" authors = ["Andrea Fioraldi "] description = "Common code for target instrumentation that can be used combined with LibAFL" documentation = "https://docs.rs/libafl_targets" From 9ae13eb5da4f78beaf9df6a636db45227c4341f1 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 12:21:15 +0200 Subject: [PATCH 17/43] clippy --- libafl/src/observers/cmp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 4f0cd4c18d..0ae3cf4db5 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -37,10 +37,10 @@ impl CmpValues { pub fn to_u64_tuple(&self) -> Option<(u64, u64)> { match self { - CmpValues::U8(t) => Some((t.0 as u64, t.1 as u64)), - CmpValues::U16(t) => Some((t.0 as u64, t.1 as u64)), - CmpValues::U32(t) => Some((t.0 as u64, t.1 as u64)), - CmpValues::U64(t) => Some((t.0 as u64, t.1 as u64)), + 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((u64::from(t.0), u64::from(t.1))), _ => None, } } From e719e85ababfbbc6471627718a7a833d9331947e Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 13:16:47 +0200 Subject: [PATCH 18/43] clippy --- libafl/src/mutators/token_mutations.rs | 11 ++++--- libafl/src/observers/cmp.rs | 42 +++++++++++++++++++------- libafl_targets/src/cmplog.rs | 2 +- libafl_targets/src/sancov_pcguard.rs | 2 +- 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index c50e671c11..5223155a8e 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -310,6 +310,7 @@ where S: HasMetadata + HasRand + HasMaxSize, R: Rand, { + #[allow(clippy::too_many_lines)] fn mutate( &mut self, state: &mut S, @@ -343,13 +344,13 @@ where let mut result = MutationResult::Skipped; match cmp_values { CmpValues::U8(v) => { - for i in off..len { - if bytes[i] == v.0 { - bytes[i] = v.1; + for byte in bytes.iter_mut().take(len).skip(off) { + if *byte == v.0 { + *byte = v.1; result = MutationResult::Mutated; break; - } else if bytes[i] == v.1 { - bytes[i] = v.0; + } else if *byte == v.1 { + *byte = v.0; result = MutationResult::Mutated; break; } diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index 0ae3cf4db5..a202b49705 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -25,29 +25,28 @@ pub enum CmpValues { } impl CmpValues { + #[must_use] pub fn is_numeric(&self) -> bool { - match self { - CmpValues::U8(_) => true, - CmpValues::U16(_) => true, - CmpValues::U32(_) => true, - CmpValues::U64(_) => true, - _ => false, - } + 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((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(Serialize, Deserialize)] +#[derive(Default, Serialize, Deserialize)] pub struct CmpValuesMetadata { /// A `list` of values. pub list: Vec, @@ -76,10 +75,19 @@ 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 + } + + // Get the number of executions for a cmp fn executions_for(&self, idx: usize) -> usize; + // Get the number of logged executions for a cmp fn usable_executions_for(&self, idx: usize) -> usize; + // Get the logged values for a cmp fn values_of(&self, idx: usize, execution: usize) -> CmpValues; /// Reset the state @@ -94,10 +102,14 @@ where /// 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, @@ -221,7 +233,7 @@ impl<'a, CM> StdCmpObserver<'a, CM> where CM: CmpMap, { - /// Creates a new [`StdCmpObserver`] with the given name. + /// Creates a new [`StdCmpObserver`] with the given name and map. #[must_use] pub fn new(name: &'static str, map: &'a mut CM) -> Self { Self { @@ -231,5 +243,13 @@ where } } - // TODO with_size + /// 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/src/cmplog.rs b/libafl_targets/src/cmplog.rs index e217bfb7ce..8f975c716f 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -144,7 +144,7 @@ pub static mut libafl_cmplog_enabled: u8 = 0; pub use libafl_cmplog_enabled as CMPLOG_ENABLED; -/// A [`CmpObserver`] observer for CmpLog +/// A [`CmpObserver`] observer for `CmpLog` #[derive(Serialize, Deserialize, Debug)] pub struct CmpLogObserver<'a> { map: OwnedRefMut<'a, CmpLogMap>, diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 4c4ffecf7e..6d5f6dcc19 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -1,6 +1,6 @@ //! [`LLVM` `PcGuard`](https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs-with-guards) runtime for `LibAFL`. -use crate::coverage::*; +use crate::coverage::{EDGES_MAP, EDGES_MAP_SIZE, MAX_EDGES_NUM}; #[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] #[cfg(not(any(doc, feature = "clippy")))] From b999f45caa2d97b7df05443689cd40703f8a800c Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 13:54:39 +0200 Subject: [PATCH 19/43] no clippy for fuzzers/ --- scripts/build_all_fuzzers.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/build_all_fuzzers.sh b/scripts/build_all_fuzzers.sh index 6c6586d176..4e1c9c83a5 100755 --- a/scripts/build_all_fuzzers.sh +++ b/scripts/build_all_fuzzers.sh @@ -8,10 +8,10 @@ cd fuzzers for fuzzer in *; do - echo "[+] Checking fmt and building $fuzzer" + echo "[+] Checking fmt, and building $fuzzer" cd $fuzzer \ && cargo fmt --all -- --check \ - && cargo clippy \ + # && ../../clippy.sh --no-clean \ # No clippy for example fuzzers && cargo build \ && cd .. \ || exit 1 From e6b95c1a4cac65aeb0132497987637a6a2ee14af Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Thu, 20 May 2021 14:04:22 +0200 Subject: [PATCH 20/43] fix --- scripts/build_all_fuzzers.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/build_all_fuzzers.sh b/scripts/build_all_fuzzers.sh index 4e1c9c83a5..b070178f53 100755 --- a/scripts/build_all_fuzzers.sh +++ b/scripts/build_all_fuzzers.sh @@ -8,10 +8,9 @@ cd fuzzers for fuzzer in *; do - echo "[+] Checking fmt, and building $fuzzer" + echo "[+] Checking fmt and building $fuzzer" cd $fuzzer \ && cargo fmt --all -- --check \ - # && ../../clippy.sh --no-clean \ # No clippy for example fuzzers && cargo build \ && cd .. \ || exit 1 From 2bbff1b7abcdf43338326052c14b65bc163d5b4b Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 9 May 2021 10:14:17 +0300 Subject: [PATCH 21/43] add cmplog runtime instrumentation --- libafl_frida/src/cmplog_rt.rs | 187 ++++++++++++++++ libafl_frida/src/helper.rs | 399 +++++++++++++++++++++++++++++++++- libafl_frida/src/lib.rs | 17 +- 3 files changed, 598 insertions(+), 5 deletions(-) create mode 100644 libafl_frida/src/cmplog_rt.rs diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs new file mode 100644 index 0000000000..8bd66fac73 --- /dev/null +++ b/libafl_frida/src/cmplog_rt.rs @@ -0,0 +1,187 @@ +use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; +use nix::{ + libc::{memmove, memset}, + sys::mman::{mmap, MapFlags, ProtFlags}, +}; +use std::ffi::c_void; + +// TODO compile time flag +//pub const CMPLOG_MAP_W: usize = 65536; +pub const CMPLOG_MAP_W: usize = 8000; +pub const CMPLOG_MAP_H: usize = 32; +pub const CMPLOG_MAP_SIZE: usize = CMPLOG_MAP_W * CMPLOG_MAP_H; + +pub const CMPLOG_KIND_INS: u8 = 0; +pub const CMPLOG_KIND_RTN: u8 = 1; + +extern crate libafl_targets; +extern "C" { + pub fn __sanitizer_cov_trace_cmp8(arg1: u64, arg2: u64); +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CmpLogHeader { + hits: u16, + shape: u8, + kind: u8, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CmpLogOperands(u64, u64); + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct CmpLogMap { + headers: [CmpLogHeader; CMPLOG_MAP_W], + operands: [CmpLogOperands; CMPLOG_MAP_W], +} + +#[no_mangle] +pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { + headers: [CmpLogHeader { + hits: 0, + shape: 0, + kind: 0, + }; CMPLOG_MAP_W], + operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], +}; + +pub use libafl_cmplog_map as CMPLOG_MAP; + +#[no_mangle] +pub static mut libafl_cmplog_enabled: u8 = 0; + +pub use libafl_cmplog_enabled as CMPLOG_ENABLED; + +pub struct CmpLogRuntime { + regs: [u64; 2], + cmp_idx: usize, + cmplog_map: CmpLogMap, + ops_save_register_and_blr_to_populate: Option>, +} + +impl CmpLogRuntime { + pub fn new() -> CmpLogRuntime { + Self { + regs: [0; 2], + cmp_idx: 0, + cmplog_map: CmpLogMap { + headers: [CmpLogHeader { + hits: 0, + shape: 0, + kind: 0, + }; CMPLOG_MAP_W], + operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], + }, + ops_save_register_and_blr_to_populate: None, + } + } + + extern "C" fn populate_lists(&mut self) { + let op1 = self.regs[0]; + let op2 = self.regs[1]; + + self.cmplog_map.headers[self.cmp_idx].hits += 1; + self.cmplog_map.headers[self.cmp_idx].shape = 8; + let cmplog_ops: CmpLogOperands = CmpLogOperands(op1, op2); + self.cmplog_map.operands[self.cmp_idx] = cmplog_ops; + self.cmp_idx += 1; + } + + /// Generate the instrumentation blobs for the current arch. + fn generate_instrumentation_blobs(&mut self) { + macro_rules! blr_to_populate { + ($ops:ident, $bit:expr) => {dynasm!($ops + ; .arch aarch64 + ; stp x2, x3, [sp, #-0x10]! + ; stp x4, x5, [sp, #-0x10]! + ; stp x6, x7, [sp, #-0x10]! + ; stp x8, x9, [sp, #-0x10]! + ; stp x10, x11, [sp, #-0x10]! + ; stp x12, x13, [sp, #-0x10]! + ; stp x14, x15, [sp, #-0x10]! + ; stp x16, x17, [sp, #-0x10]! + ; stp x18, x19, [sp, #-0x10]! + ; stp x20, x21, [sp, #-0x10]! + ; stp x22, x23, [sp, #-0x10]! + ; stp x24, x25, [sp, #-0x10]! + ; stp x26, x27, [sp, #-0x10]! + ; stp x28, x29, [sp, #-0x10]! + ; stp x30, xzr, [sp, #-0x10]! + // jump to rust based population of the lists + // ; ldr x2, >self_regs_addr + // ; stp x0, x1, [x2] + // jump to c implementation of cmplog pupolation + ; ldr x2, >populate_lists + ; blr x2 + ; ldp x30, xzr, [sp], #0x10 + ; ldp x28, x29, [sp], #0x10 + ; ldp x26, x27, [sp], #0x10 + ; ldp x24, x25, [sp], #0x10 + ; ldp x22, x23, [sp], #0x10 + ; ldp x20, x21, [sp], #0x10 + ; ldp x18, x19, [sp], #0x10 + ; ldp x16, x17, [sp], #0x10 + ; ldp x14, x15, [sp], #0x10 + ; ldp x12, x13, [sp], #0x10 + ; ldp x10, x11, [sp], #0x10 + ; ldp x8, x9, [sp], #0x10 + ; ldp x6, x7, [sp], #0x10 + ; ldp x4, x5, [sp], #0x10 + ; ldp x2, x3, [sp], #0x10 + ; b >done + ; self_regs_addr: //for rust based population of the lists.. + ; .qword &mut self.regs as *mut _ as *mut c_void as i64 + ; populate_lists: + ; .qword __sanitizer_cov_trace_cmp8 as *mut c_void as i64 + ; done: + );}; + } + + let mut ops_save_register_and_blr_to_populate = + dynasmrt::VecAssembler::::new(0); + blr_to_populate!(ops_save_register_and_blr_to_populate, 0); + + self.ops_save_register_and_blr_to_populate = Some( + ops_save_register_and_blr_to_populate + .finalize() + .unwrap() + .into_boxed_slice(), + ); + } + pub fn init(&mut self) { + // workaround frida's frida-gum-allocate-near bug: + unsafe { + for _ in 0..64 { + mmap( + std::ptr::null_mut(), + 128 * 1024, + ProtFlags::PROT_NONE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .expect("Failed to map dummy regions for frida workaround"); + mmap( + std::ptr::null_mut(), + 4 * 1024 * 1024, + ProtFlags::PROT_NONE, + MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, + -1, + 0, + ) + .expect("Failed to map dummy regions for frida workaround"); + } + } + + self.generate_instrumentation_blobs(); + } + + /// Get the blob which saves the context, jumps to the populate function and restores the context + #[inline] + pub fn ops_save_register_and_blr_to_populate(&self) -> &[u8] { + self.ops_save_register_and_blr_to_populate.as_ref().unwrap() + } +} diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index be3046cc79..daf44cdaab 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -37,7 +37,14 @@ use std::path::PathBuf; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use crate::{asan_rt::AsanRuntime, FridaOptions}; +use crate::{asan_rt::AsanRuntime, cmplog_rt::CmpLogRuntime, FridaOptions}; + +enum CmplogOperandType { + Regid(capstone::RegId), + Imm(u64), + Cimm(u64), + Mem(capstone::RegId, capstone::RegId, i32, u32), +} /// An helper that feeds [`FridaInProcessExecutor`] with user-supplied instrumentation pub trait FridaHelper<'a> { @@ -76,7 +83,8 @@ pub struct FridaInstrumentationHelper<'a> { transformer: Option>, #[cfg(target_arch = "aarch64")] capstone: Capstone, - asan_runtime: AsanRuntime, + asan_runtime: Rc>, + cmplog_runtime: CmpLogRuntime, ranges: RangeMap, options: &'a FridaOptions, drcov_basic_blocks: Vec, @@ -261,6 +269,7 @@ impl<'a> FridaInstrumentationHelper<'a> { .build() .expect("Failed to create Capstone object"), asan_runtime: AsanRuntime::new(options.clone()), + cmplog_runtime: CmpLogRuntime::new(), ranges: RangeMap::new(), options, drcov_basic_blocks: vec![], @@ -331,7 +340,7 @@ impl<'a> FridaInstrumentationHelper<'a> { todo!("Implement ASAN for non-aarch64 targets"); #[cfg(target_arch = "aarch64")] if let Ok((basereg, indexreg, displacement, width, shift, extender)) = - helper.is_interesting_instruction(address, instr) + helper.is_interesting_asan_instruction(address, instr) { helper.emit_shadow_check( address, @@ -345,6 +354,18 @@ impl<'a> FridaInstrumentationHelper<'a> { ); } } + + if helper.options().cmplog_enabled() { + // check if this instruction is a compare instruction and if so save the registers values + if let Ok((op1, op2)) = + helper.is_interesting_cmplog_instruction(address, instr) + { + println!("emmiting at {} => {}", address, instr); + //emit code that saves the relevant data in runtime(passes it to x0, x1) + helper.emit_comparison_handling(address, &output, op1, op2); + } + } + if helper.options().asan_enabled() || helper.options().drcov_enabled() { helper.asan_runtime.add_stalked_address( output.writer().pc() as usize - 4, @@ -359,6 +380,9 @@ impl<'a> FridaInstrumentationHelper<'a> { if helper.options().asan_enabled() || helper.options().drcov_enabled() { helper.asan_runtime.init(gum, modules_to_instrument); } + if helper.options.cmplog_enabled() { + helper.cmplog_runtime.init(); + } } helper } @@ -374,6 +398,311 @@ impl<'a> FridaInstrumentationHelper<'a> { Aarch64Register::from_u32(regint as u32).unwrap() } + #[cfg(target_arch = "aarch64")] + #[inline] + fn emit_comparison_handling( + &self, + _address: u64, + output: &StalkerOutput, + op1: CmplogOperandType, + op2: CmplogOperandType, + ) { + let writer = output.writer(); + + // Preserve x0, x1: + writer.put_stp_reg_reg_reg_offset( + Aarch64Register::X0, + Aarch64Register::X1, + Aarch64Register::Sp, + -(16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i32) as i64, + IndexMode::PreAdjust, + ); + + // make sure operand1 value is saved into x0 + match op1 { + CmplogOperandType::Imm(value) | CmplogOperandType::Cimm(value) => { + writer.put_ldr_reg_u64(Aarch64Register::X0, value); + } + CmplogOperandType::Regid(reg) => { + let reg = self.get_writer_register(reg); + match reg { + Aarch64Register::X0 | Aarch64Register::W0 => {} + Aarch64Register::X1 | Aarch64Register::W1 => { + writer.put_mov_reg_reg(Aarch64Register::X0, Aarch64Register::X1); + } + _ => { + if !writer.put_mov_reg_reg(Aarch64Register::X0, reg) { + writer.put_mov_reg_reg(Aarch64Register::W0, reg); + } + } + } + } + CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { + let basereg = self.get_writer_register(basereg); + let indexreg = if indexreg.0 != 0 { + Some(self.get_writer_register(indexreg)) + } else { + None + }; + + // calculate base+index+displacment into x0 + let displacement = displacement + + if basereg == Aarch64Register::Sp { + 16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i32 + } else { + 0 + }; + + if indexreg.is_some() { + if let Some(indexreg) = indexreg { + writer.put_add_reg_reg_reg(Aarch64Register::X0, basereg, indexreg); + } + } else { + match basereg { + Aarch64Register::X0 | Aarch64Register::W0 => {} + Aarch64Register::X1 | Aarch64Register::W1 => { + writer.put_mov_reg_reg(Aarch64Register::X0, Aarch64Register::X1); + } + _ => { + if !writer.put_mov_reg_reg(Aarch64Register::X0, basereg) { + writer.put_mov_reg_reg(Aarch64Register::W0, basereg); + } + } + } + } + + //add displacement + writer.put_add_reg_reg_imm( + Aarch64Register::X0, + Aarch64Register::X0, + displacement as u64, + ); + + //deref into x0 to get the real value + writer.put_ldr_reg_reg_offset(Aarch64Register::X0, Aarch64Register::X0, 0u64); + } + } + + // make sure operand2 value is saved into x1 + match op2 { + CmplogOperandType::Imm(value) | CmplogOperandType::Cimm(value) => { + writer.put_ldr_reg_u64(Aarch64Register::X1, value); + } + CmplogOperandType::Regid(reg) => { + let reg = self.get_writer_register(reg); + match reg { + Aarch64Register::X1 | Aarch64Register::W1 => {} + Aarch64Register::X0 | Aarch64Register::W0 => { + writer.put_ldr_reg_reg_offset( + Aarch64Register::X1, + Aarch64Register::Sp, + 0u64, + ); + } + _ => { + if !writer.put_mov_reg_reg(Aarch64Register::X1, reg) { + writer.put_mov_reg_reg(Aarch64Register::W1, reg); + } + } + } + } + CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { + let basereg = self.get_writer_register(basereg); + let indexreg = if indexreg.0 != 0 { + Some(self.get_writer_register(indexreg)) + } else { + None + }; + + // calculate base+index+displacment into x1 + let displacement = displacement + + if basereg == Aarch64Register::Sp { + 16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i32 + } else { + 0 + }; + + if indexreg.is_some() { + if let Some(indexreg) = indexreg { + match indexreg { + Aarch64Register::X0 | Aarch64Register::W0 => { + match basereg { + Aarch64Register::X1 | Aarch64Register::W1 => { + // x0 is overwrittern indexreg by op1 value. + // x1 is basereg + + // Preserve x2, x3: + writer.put_stp_reg_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::X3, + Aarch64Register::Sp, + -(16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i32) as i64, + IndexMode::PreAdjust, + ); + + //reload indexreg to x2 + writer.put_ldr_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::Sp, + 0u64, + ); + //add them into basereg==x1 + writer.put_add_reg_reg_reg( + basereg, + basereg, + Aarch64Register::X2, + ); + + // Restore x2, x3 + assert!(writer.put_ldp_reg_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::X3, + Aarch64Register::Sp, + 16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i64, + IndexMode::PostAdjust, + )); + } + _ => { + // x0 is overwrittern indexreg by op1 value. + // basereg is not x1 nor x0 + + //reload indexreg to x1 + writer.put_ldr_reg_reg_offset( + Aarch64Register::X1, + Aarch64Register::Sp, + 0u64, + ); + //add basereg into indexreg==x1 + writer.put_add_reg_reg_reg( + Aarch64Register::X1, + basereg, + Aarch64Register::X1, + ); + } + } + } + Aarch64Register::X1 | Aarch64Register::W1 => { + match basereg { + Aarch64Register::X0 | Aarch64Register::W0 => { + // x0 is overwrittern basereg by op1 value. + // x1 is indexreg + + // Preserve x2, x3: + writer.put_stp_reg_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::X3, + Aarch64Register::Sp, + -(16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i32) as i64, + IndexMode::PreAdjust, + ); + + //reload basereg to x2 + writer.put_ldr_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::Sp, + 0u64, + ); + //add basereg into indexreg==x1 + writer.put_add_reg_reg_reg( + indexreg, + Aarch64Register::X2, + indexreg, + ); + + // Restore x2, x3 + assert!(writer.put_ldp_reg_reg_reg_offset( + Aarch64Register::X2, + Aarch64Register::X3, + Aarch64Register::Sp, + 16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i64, + IndexMode::PostAdjust, + )); + } + _ => { + // indexreg is x1 + // basereg is not x0 and not x1 + + //add them into x1 + writer.put_add_reg_reg_reg(indexreg, basereg, indexreg); + } + } + } + _ => { + match basereg { + Aarch64Register::X0 | Aarch64Register::W0 => { + //basereg is overwrittern by op1 value + //index reg is not x0 nor x1 + + //reload basereg to x1 + writer.put_ldr_reg_reg_offset( + Aarch64Register::X1, + Aarch64Register::Sp, + 0u64, + ); + //add indexreg to basereg==x1 + writer.put_add_reg_reg_reg( + Aarch64Register::X1, + Aarch64Register::X1, + indexreg, + ); + } + _ => { + //basereg is not x0, can be x1 + //index reg is not x0 nor x1 + + //add them into x1 + writer.put_add_reg_reg_reg( + Aarch64Register::X1, + basereg, + indexreg, + ); + } + } + } + } + } + } else { + match basereg { + Aarch64Register::X1 | Aarch64Register::W1 => {} + Aarch64Register::X0 | Aarch64Register::W0 => { + // x0 is overwrittern basereg by op1 value. + //reload basereg to x1 + writer.put_ldr_reg_reg_offset( + Aarch64Register::X1, + Aarch64Register::Sp, + 0u64, + ); + } + _ => { + writer.put_mov_reg_reg(Aarch64Register::W1, basereg); + } + } + } + + // add displacement + writer.put_add_reg_reg_imm( + Aarch64Register::X1, + Aarch64Register::X1, + displacement as u64, + ); + //deref into x1 to get the real value + writer.put_ldr_reg_reg_offset(Aarch64Register::X1, Aarch64Register::X1, 0u64); + } + } + + //call cmplog runtime to populate the values map + writer.put_bytes(&self.cmplog_runtime.ops_save_register_and_blr_to_populate()); + + // Restore x0, x1 + assert!(writer.put_ldp_reg_reg_reg_offset( + Aarch64Register::X0, + Aarch64Register::X1, + Aarch64Register::Sp, + 16 + frida_gum_sys::GUM_RED_ZONE_SIZE as i64, + IndexMode::PostAdjust, + )); + } + #[cfg(target_arch = "aarch64")] #[inline] fn emit_shadow_check( @@ -651,7 +980,7 @@ impl<'a> FridaInstrumentationHelper<'a> { #[cfg(target_arch = "aarch64")] #[inline] - fn is_interesting_instruction( + fn is_interesting_asan_instruction( &self, _address: u64, instr: &Insn, @@ -701,6 +1030,68 @@ impl<'a> FridaInstrumentationHelper<'a> { Err(()) } + #[inline] + fn is_interesting_cmplog_instruction( + &self, + _address: u64, + instr: &Insn, + ) -> Result<(CmplogOperandType, CmplogOperandType), ()> { + // We only care for compare instrunctions - aka instructions which set the flags + match instr.mnemonic().unwrap() { + "cmp" | "ands" | "subs" | "adds" | "negs" | "ngcs" | "sbcs" | "bics" | "cls" => (), + _ => return Err(()), + } + let operands = self + .capstone + .insn_detail(instr) + .unwrap() + .arch_detail() + .operands(); + if operands.len() != 2 { + return Err(()); + } + + let operand1 = if let Arm64Operand(arm64operand) = operands.first().unwrap() { + match arm64operand.op_type { + Arm64OperandType::Reg(regid) => Some(CmplogOperandType::Regid(regid)), + Arm64OperandType::Imm(val) => Some(CmplogOperandType::Imm(val as u64)), + Arm64OperandType::Mem(opmem) => Some(CmplogOperandType::Mem( + opmem.base(), + opmem.index(), + opmem.disp(), + self.get_instruction_width(instr, &operands), + )), + Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), + _ => return Err(()), + } + } else { + None + }; + + let operand2 = if let Arm64Operand(arm64operand2) = operands.last().unwrap() { + match arm64operand2.op_type { + Arm64OperandType::Reg(regid) => Some(CmplogOperandType::Regid(regid)), + Arm64OperandType::Imm(val) => Some(CmplogOperandType::Imm(val as u64)), + Arm64OperandType::Mem(opmem) => Some(CmplogOperandType::Mem( + opmem.base(), + opmem.index(), + opmem.disp(), + self.get_instruction_width(instr, &operands), + )), + Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), + _ => return Err(()), + } + } else { + None + }; + + if operand1.is_some() && operand2.is_some() { + Ok((operand1.unwrap(), operand2.unwrap())) + } else { + Err(()) + } + } + #[inline] fn emit_coverage_mapping(&mut self, address: u64, output: &StalkerOutput) { let writer = output.writer(); diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index c6f0f47b06..876a8713c1 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -9,7 +9,11 @@ pub mod alloc; pub mod asan_errors; /// The frida address sanitizer runtime pub mod asan_rt; -/// The `LibAFL` frida helper + +/// The frida cmplog runtime +pub mod cmplog_rt; + +/// The `LibAFL` firda helper pub mod helper; // for parsing asan cores @@ -28,6 +32,7 @@ pub struct FridaOptions { enable_coverage: bool, enable_drcov: bool, instrument_suppress_locations: Option>, + enable_cmplog: bool, } impl FridaOptions { @@ -100,6 +105,9 @@ impl FridaOptions { ); } } + "cmplog" => { + options.enable_cmplog = value.parse().unwrap(); + } _ => { panic!("unknown FRIDA option: '{}'", option); } @@ -144,6 +152,12 @@ impl FridaOptions { self.enable_drcov } + /// Is CmpLog enabled? + #[inline] + pub fn cmplog_enabled(&self) -> bool { + self.enable_cmplog + } + /// Should ASAN detect leaks #[must_use] #[inline] @@ -190,6 +204,7 @@ impl Default for FridaOptions { enable_coverage: true, enable_drcov: false, instrument_suppress_locations: None, + enable_cmplog: true, } } } From 85a90c7d21399f39e954effdf5bf23005b73cdfc Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 9 May 2021 10:14:59 +0300 Subject: [PATCH 22/43] test cmplog against value profile feature --- Cargo.toml | 3 +-- fuzzers/frida_libpng/Cargo.toml | 1 + fuzzers/frida_libpng/harness.cc | 17 +++++++++++++++-- libafl_frida/Cargo.toml | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 991821b677..d6cc4c42ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,14 +12,13 @@ members = [ "libafl_targets", "libafl_frida", "libafl_tests", + "fuzzers/frida_libpng", ] default-members = [ "libafl", "libafl_derive", "libafl_cc", "libafl_targets", - "libafl_tests", ] exclude = [ - "fuzzers", ] diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index d2227e5837..61d77a3c58 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -25,6 +25,7 @@ libafl = { path = "../../libafl/", features = [ "std", "llmp_bind_public" ] } #, libafl_frida = { path = "../../libafl_frida" } capstone = "0.8.0" frida-gum = { version = "0.5.1", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } +libafl_targets = { path = "../../libafl_targets", version = "0.1.0" , features = ["value_profile"] } lazy_static = "1.4.0" libc = "0.2" libloading = "0.7.0" diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index ed74911b58..808e66113a 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -101,14 +101,27 @@ void func2() { } __attribute__((noinline)) void func1() { - //printf("func1\n"); + //printf("func1\n"); func2(); } // Entry point for LibFuzzer. // Roughly follows the libpng book example: // http://www.libpng.org/pub/png/book/chapter13.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if (size < kPngHeaderSize) { + + if(data[10] == 0xAB && + data[11] == 0xCD && + data[12] == 0xEF && + data[13] == 0xAA && + data[14] == 0xBB ) { + printf("passed the test!"); + } else { + printf("x"); + return 0; + } + + + if (size < kPngHeaderSize) { return 0; } diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index 86ef12dc73..d1ad107e1a 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -15,7 +15,7 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] libafl = { path = "../libafl", version = "0.3.1", features = ["std", "libafl_derive"] } -libafl_targets = { path = "../libafl_targets", version = "0.3.1" } +libafl_targets = { path = "../libafl_targets", version = "0.3.1", features = ["cmplog"] } nix = "0.20.0" libc = "0.2.92" hashbrown = "0.11" From 8b2e86e7e6b8029c876e64237fff9ba6cf8264eb Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 9 May 2021 18:12:13 +0300 Subject: [PATCH 23/43] fix compile error --- libafl_frida/src/helper.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index daf44cdaab..0a7b658371 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -424,7 +424,7 @@ impl<'a> FridaInstrumentationHelper<'a> { writer.put_ldr_reg_u64(Aarch64Register::X0, value); } CmplogOperandType::Regid(reg) => { - let reg = self.get_writer_register(reg); + let reg = self.writer_register(reg); match reg { Aarch64Register::X0 | Aarch64Register::W0 => {} Aarch64Register::X1 | Aarch64Register::W1 => { @@ -438,9 +438,9 @@ impl<'a> FridaInstrumentationHelper<'a> { } } CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { - let basereg = self.get_writer_register(basereg); + let basereg = self.writer_register(basereg); let indexreg = if indexreg.0 != 0 { - Some(self.get_writer_register(indexreg)) + Some(self.writer_register(indexreg)) } else { None }; @@ -489,7 +489,7 @@ impl<'a> FridaInstrumentationHelper<'a> { writer.put_ldr_reg_u64(Aarch64Register::X1, value); } CmplogOperandType::Regid(reg) => { - let reg = self.get_writer_register(reg); + let reg = self.writer_register(reg); match reg { Aarch64Register::X1 | Aarch64Register::W1 => {} Aarch64Register::X0 | Aarch64Register::W0 => { @@ -507,9 +507,9 @@ impl<'a> FridaInstrumentationHelper<'a> { } } CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { - let basereg = self.get_writer_register(basereg); + let basereg = self.writer_register(basereg); let indexreg = if indexreg.0 != 0 { - Some(self.get_writer_register(indexreg)) + Some(self.writer_register(indexreg)) } else { None }; @@ -1059,7 +1059,7 @@ impl<'a> FridaInstrumentationHelper<'a> { opmem.base(), opmem.index(), opmem.disp(), - self.get_instruction_width(instr, &operands), + self.instruction_width(instr, &operands), )), Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), _ => return Err(()), @@ -1076,7 +1076,7 @@ impl<'a> FridaInstrumentationHelper<'a> { opmem.base(), opmem.index(), opmem.disp(), - self.get_instruction_width(instr, &operands), + self.instruction_width(instr, &operands), )), Arm64OperandType::Cimm(val) => Some(CmplogOperandType::Cimm(val as u64)), _ => return Err(()), From 2c0548a757844e7e7ff93cbe79528c80922dc73e Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 9 May 2021 19:01:34 +0300 Subject: [PATCH 24/43] add target arch aarch64 for is_interesting_cmplog_instruction --- libafl_frida/src/helper.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 0a7b658371..0562776288 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -1030,6 +1030,7 @@ impl<'a> FridaInstrumentationHelper<'a> { Err(()) } + #[cfg(target_arch = "aarch64")] #[inline] fn is_interesting_cmplog_instruction( &self, From 23b2b4a06e91b79ce61887fc64a4f70e3ab52806 Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 9 May 2021 19:15:07 +0300 Subject: [PATCH 25/43] add cfg target aarch64 on cmplog related code within stalker loop --- libafl_frida/src/helper.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index 0562776288..a4406937f5 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -356,6 +356,9 @@ impl<'a> FridaInstrumentationHelper<'a> { } if helper.options().cmplog_enabled() { + #[cfg(not(target_arch = "aarch64"))] + todo!("Implement cmplog for non-aarch64 targets"); + #[cfg(target_arch = "aarch64")] // check if this instruction is a compare instruction and if so save the registers values if let Ok((op1, op2)) = helper.is_interesting_cmplog_instruction(address, instr) From b59752eba58c7bb02ac3b3e67956fa63b40d3cdd Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 23 May 2021 11:50:23 +0300 Subject: [PATCH 26/43] revert changes in cargo.toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index d6cc4c42ca..1e703edc19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,4 +21,5 @@ default-members = [ "libafl_targets", ] exclude = [ +# "fuzzers" ] From 5bd08a6eee818b64452f78b0cedf6fb1404f8b55 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 26 May 2021 18:12:59 +0300 Subject: [PATCH 27/43] align code with 'main' branch --- fuzzers/baby_fuzzer/Cargo.toml | 2 +- fuzzers/frida_libpng/Cargo.toml | 8 +- fuzzers/libfuzzer_libmozjpeg/Cargo.toml | 2 +- fuzzers/libfuzzer_libmozjpeg/src/lib.rs | 1 + fuzzers/libfuzzer_libpng/Cargo.toml | 2 +- fuzzers/libfuzzer_libpng/src/lib.rs | 1 + fuzzers/libfuzzer_libpng_launcher/Cargo.toml | 2 +- fuzzers/libfuzzer_libpng_launcher/src/lib.rs | 1 + fuzzers/libfuzzer_reachability/Cargo.toml | 2 +- fuzzers/libfuzzer_stb_image/Cargo.toml | 2 +- fuzzers/libfuzzer_stb_image/src/main.rs | 2 +- libafl/Cargo.toml | 4 +- libafl/src/events/llmp.rs | 14 +++- libafl/src/executors/combined.rs | 86 +++++--------------- libafl/src/executors/mod.rs | 2 - libafl/src/stages/tracing.rs | 32 ++------ libafl_cc/Cargo.toml | 2 +- libafl_derive/Cargo.toml | 2 +- libafl_frida/Cargo.toml | 4 +- libafl_frida/src/helper.rs | 2 +- libafl_targets/Cargo.toml | 4 +- scripts/build_all_fuzzers.sh | 1 + 22 files changed, 64 insertions(+), 114 deletions(-) diff --git a/fuzzers/baby_fuzzer/Cargo.toml b/fuzzers/baby_fuzzer/Cargo.toml index 97fe602b1b..1d8aedf13d 100644 --- a/fuzzers/baby_fuzzer/Cargo.toml +++ b/fuzzers/baby_fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index 61d77a3c58..4ddc29b2a1 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frida_libpng" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" build = "build.rs" @@ -21,11 +21,11 @@ num_cpus = "1.0" which = "4.1" [target.'cfg(unix)'.dependencies] -libafl = { path = "../../libafl/", features = [ "std", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} -libafl_frida = { path = "../../libafl_frida" } +libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} capstone = "0.8.0" frida-gum = { version = "0.5.1", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } -libafl_targets = { path = "../../libafl_targets", version = "0.1.0" , features = ["value_profile"] } +libafl_frida = { path = "../../libafl_frida", version = "0.3.2" } +libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] } lazy_static = "1.4.0" libc = "0.2" libloading = "0.7.0" diff --git a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml index f166ef35fa..6137d50894 100644 --- a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml +++ b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libmozjpeg" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs index fb4782cf02..7f68c7ed63 100644 --- a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs @@ -15,6 +15,7 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, + inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::StdMapObserver, diff --git a/fuzzers/libfuzzer_libpng/Cargo.toml b/fuzzers/libfuzzer_libpng/Cargo.toml index 39252a73a6..5c38cd2133 100644 --- a/fuzzers/libfuzzer_libpng/Cargo.toml +++ b/fuzzers/libfuzzer_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index ca1011ad7d..411768118b 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -16,6 +16,7 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, + inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml index 289b80606c..b8466488f2 100644 --- a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng_launcher" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs index 9384e434da..996ec170bb 100644 --- a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs @@ -24,6 +24,7 @@ use libafl::{ feedback_or, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, + inputs::{BytesInput, HasTargetBytes}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, diff --git a/fuzzers/libfuzzer_reachability/Cargo.toml b/fuzzers/libfuzzer_reachability/Cargo.toml index 044a57420a..c04a484e59 100644 --- a/fuzzers/libfuzzer_reachability/Cargo.toml +++ b/fuzzers/libfuzzer_reachability/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_reachability" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index 8bdfb95cf8..ea49909a65 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_stb_image" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" build = "build.rs" diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index c3e3d6b88b..5fca306e93 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -20,7 +20,7 @@ use libafl::{ observers::{StdMapObserver, TimeObserver}, stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, StdState}, - stats::SimpleStats, + stats::MultiStats, Error, }; diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index a5d663fe1e..58f57ea890 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi ", "Dominik Maier "] description = "Slot your own fuzzers together and extend their features using Rust" documentation = "https://docs.rs/libafl" @@ -52,7 +52,7 @@ path = "./examples/llmp_test/main.rs" required-features = ["std"] [dependencies] -libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.1" } +libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.2" } tuple_list = "0.1.2" hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible num = "0.4.0" diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 86ff0c984e..35dc577669 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -170,7 +170,7 @@ where let client = stats.client_stats_mut_for(sender_id); client.update_corpus_size(*corpus_size as u64); client.update_executions(*executions as u64, *time); - stats.display(event.name().to_string() + " #" + &sender_id.to_string()); + stats.display(event.name().to_string(), sender_id); Ok(BrokerEventResult::Forward) } Event::UpdateStats { @@ -181,7 +181,17 @@ where // TODO: The stats buffer should be added on client add. let client = stats.client_stats_mut_for(sender_id); client.update_executions(*executions as u64, *time); - stats.display(event.name().to_string() + " #" + &sender_id.to_string()); + stats.display(event.name().to_string(), sender_id); + Ok(BrokerEventResult::Handled) + } + Event::UpdateUserStats { + name, + value, + phantom: _, + } => { + let client = stats.client_stats_mut_for(sender_id); + client.update_user_stats(name.clone(), value.clone()); + stats.display(event.name().to_string(), sender_id); Ok(BrokerEventResult::Handled) } #[cfg(feature = "introspection")] diff --git a/libafl/src/executors/combined.rs b/libafl/src/executors/combined.rs index 9d208e8bac..a4ae7b3ccb 100644 --- a/libafl/src/executors/combined.rs +++ b/libafl/src/executors/combined.rs @@ -1,42 +1,22 @@ //! A `CombinedExecutor` wraps a primary executor and a secondary one -use core::marker::PhantomData; - use crate::{ - executors::{ - Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks, - }, + executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, inputs::Input, observers::ObserversTuple, Error, }; /// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one - -pub struct CombinedExecutor -where - A: Executor, - B: Executor, - I: Input, -{ +pub struct CombinedExecutor { primary: A, secondary: B, - phantom: PhantomData, } -impl CombinedExecutor -where - A: Executor, - B: Executor, - I: Input, -{ +impl CombinedExecutor { /// Create a new `CombinedExecutor`, wrapping the given `executor`s. - pub fn new(primary: A, secondary: B) -> Self { - Self { - primary, - secondary, - phantom: PhantomData, - } + pub fn new(primary: A, secondary: B) -> Self { + Self { primary, secondary } } /// Retrieve the primary `Executor` that is wrapped by this `CombinedExecutor`. @@ -50,22 +30,26 @@ where } } -impl Executor for CombinedExecutor +impl Executor for CombinedExecutor where - A: Executor, - B: Executor, + A: Executor, + B: Executor, I: Input, { - fn run_target(&mut self, input: &I) -> Result { - self.primary.run_target(input) + fn run_target( + &mut self, + fuzzer: &mut Z, + state: &mut S, + mgr: &mut EM, + input: &I, + ) -> Result { + self.primary.run_target(fuzzer, state, mgr, input) } } -impl HasObservers for CombinedExecutor +impl HasObservers for CombinedExecutor where - A: Executor + HasObservers, - B: Executor, - I: Input, + A: HasObservers, OT: ObserversTuple, { #[inline] @@ -79,40 +63,10 @@ where } } -impl HasObserversHooks for CombinedExecutor +impl HasObserversHooks for CombinedExecutor where - A: Executor + HasObservers, - B: Executor, + A: HasObservers, I: Input, OT: ObserversTuple + HasExecHooksTuple, { } - -impl HasExecHooks for CombinedExecutor -where - A: Executor + HasExecHooks, - B: Executor, - I: Input, -{ - #[inline] - fn pre_exec( - &mut self, - fuzzer: &mut Z, - state: &mut S, - mgr: &mut EM, - input: &I, - ) -> Result<(), Error> { - self.primary.pre_exec(fuzzer, state, mgr, input) - } - - #[inline] - fn post_exec( - &mut self, - fuzzer: &mut Z, - state: &mut S, - mgr: &mut EM, - input: &I, - ) -> Result<(), Error> { - self.primary.post_exec(fuzzer, state, mgr, input) - } -} diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 2b992f74da..25bcaf3c89 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -4,8 +4,6 @@ pub mod inprocess; pub use inprocess::InProcessExecutor; pub mod timeout; pub use timeout::TimeoutExecutor; -pub mod combined; -pub use combined::CombinedExecutor; #[cfg(all(feature = "std", unix))] pub mod forkserver; diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index 0ba71f6259..4e37dce554 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -2,7 +2,7 @@ use core::{marker::PhantomData, mem::drop}; use crate::{ corpus::Corpus, - executors::{Executor, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks}, + executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks}, inputs::Input, mark_feature_time, observers::ObserversTuple, @@ -21,10 +21,7 @@ pub struct TracingStage where I: Input, C: Corpus, - TE: Executor - + HasObservers - + HasExecHooks - + HasObserversHooks, + TE: Executor + HasObservers + HasObserversHooks, OT: ObserversTuple + HasExecHooksTuple, S: HasClientPerfStats + HasExecutions + HasCorpus, { @@ -37,10 +34,7 @@ impl Stage for TracingStage, - TE: Executor - + HasObservers - + HasExecHooks - + HasObserversHooks, + TE: Executor + HasObservers + HasObserversHooks, OT: ObserversTuple + HasExecHooksTuple, S: HasClientPerfStats + HasExecutions + HasCorpus, { @@ -68,19 +62,12 @@ where mark_feature_time!(state, PerfFeature::PreExecObservers); start_timer!(state); - self.tracer_executor - .pre_exec(fuzzer, state, manager, &input)?; - mark_feature_time!(state, PerfFeature::PreExec); - - start_timer!(state); - let _ = self.tracer_executor.run_target(&input)?; + drop( + self.tracer_executor + .run_target(fuzzer, state, manager, &input)?, + ); mark_feature_time!(state, PerfFeature::TargetExecution); - start_timer!(state); - self.tracer_executor - .post_exec(fuzzer, state, manager, &input)?; - mark_feature_time!(state, PerfFeature::PostExec); - *state.executions_mut() += 1; start_timer!(state); @@ -96,10 +83,7 @@ impl TracingStage where I: Input, C: Corpus, - TE: Executor - + HasObservers - + HasExecHooks - + HasObserversHooks, + TE: Executor + HasObservers + HasObserversHooks, OT: ObserversTuple + HasExecHooksTuple, S: HasClientPerfStats + HasExecutions + HasCorpus, { diff --git a/libafl_cc/Cargo.toml b/libafl_cc/Cargo.toml index 9500348ac7..302402bb0f 100644 --- a/libafl_cc/Cargo.toml +++ b/libafl_cc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_cc" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi "] description = "Commodity library to wrap compilers and link LibAFL" documentation = "https://docs.rs/libafl_cc" diff --git a/libafl_derive/Cargo.toml b/libafl_derive/Cargo.toml index 878fd34d21..36ef86f99f 100644 --- a/libafl_derive/Cargo.toml +++ b/libafl_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_derive" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi "] description = "Derive proc-macro crate for LibAFL" documentation = "https://docs.rs/libafl_derive" diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index d1ad107e1a..82a23a3995 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_frida" -version = "0.3.1" +version = "0.3.2" authors = ["s1341 "] description = "Frida backend library for LibAFL" documentation = "https://docs.rs/libafl_frida" @@ -15,7 +15,7 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] libafl = { path = "../libafl", version = "0.3.1", features = ["std", "libafl_derive"] } -libafl_targets = { path = "../libafl_targets", version = "0.3.1", features = ["cmplog"] } +libafl_targets = { path = "../libafl_targets", version = "0.3.2", features = ["sancov_cmplog"] } nix = "0.20.0" libc = "0.2.92" hashbrown = "0.11" diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index a4406937f5..aa9b2de015 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -83,7 +83,7 @@ pub struct FridaInstrumentationHelper<'a> { transformer: Option>, #[cfg(target_arch = "aarch64")] capstone: Capstone, - asan_runtime: Rc>, + asan_runtime: AsanRuntime, cmplog_runtime: CmpLogRuntime, ranges: RangeMap, options: &'a FridaOptions, diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index d053891581..c1f4eb9ded 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_targets" -version = "0.3.1" +version = "0.3.2" authors = ["Andrea Fioraldi "] description = "Common code for target instrumentation that can be used combined with LibAFL" documentation = "https://docs.rs/libafl_targets" @@ -25,6 +25,6 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] rangemap = "0.1.10" -libafl = { path = "../libafl", version = "0.3", features = [] } +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" diff --git a/scripts/build_all_fuzzers.sh b/scripts/build_all_fuzzers.sh index b070178f53..f96de961e7 100755 --- a/scripts/build_all_fuzzers.sh +++ b/scripts/build_all_fuzzers.sh @@ -11,6 +11,7 @@ do echo "[+] Checking fmt and building $fuzzer" cd $fuzzer \ && cargo fmt --all -- --check \ + && cargo clippy \ && cargo build \ && cd .. \ || exit 1 From 2a325beefffb2e2a7bf75e5cf5efdc87211e4762 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 26 May 2021 18:14:42 +0300 Subject: [PATCH 28/43] revert accidently changed Cargo.toml file --- Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e703edc19..270994e82e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,6 @@ members = [ "libafl_targets", "libafl_frida", "libafl_tests", - "fuzzers/frida_libpng", ] default-members = [ "libafl", @@ -21,5 +20,5 @@ default-members = [ "libafl_targets", ] exclude = [ -# "fuzzers" + "fuzzers" ] From ac27efb954ad7d8f9f16e92fec960003d5435f70 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 26 May 2021 18:15:09 +0300 Subject: [PATCH 29/43] update cmplog runtime code to work with the cmplog backend implementation --- fuzzers/frida_libpng/src/fuzzer.rs | 5 + libafl_frida/src/cmplog_rt.rs | 162 ++++++++++++++--------------- libafl_targets/src/sancov_cmp.c | 6 ++ 3 files changed, 89 insertions(+), 84 deletions(-) diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index c6b90170a4..3fb03f922a 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -57,6 +57,7 @@ use libafl_frida::{ helper::{FridaHelper, FridaInstrumentationHelper, MAP_SIZE}, FridaOptions, }; +use libafl_targets::cmplog::{CmpLogObserver, CMPLOG_MAP}; struct FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S> where @@ -317,6 +318,9 @@ unsafe fn fuzz( &modules_to_instrument, ); + // Create an observation channel using cmplog map + let cmplog_observer = CmpLogObserver::new("cmplog", &mut CMPLOG_MAP, true); + // Create an observation channel using the coverage map let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr( "edges", @@ -396,6 +400,7 @@ unsafe fn fuzz( tuple_list!( edges_observer, time_observer, + cmplog_observer, AsanErrorsObserver::new(&ASAN_ERRORS) ), &mut fuzzer, diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 8bd66fac73..48d38bb340 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -1,80 +1,67 @@ use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; +use libafl_targets::cmplog::{ + libafl_cmplog_map, CmpLogHeader, CmpLogMap, CmpLogOperands, CMPLOG_MAP_W, +}; use nix::{ libc::{memmove, memset}, sys::mman::{mmap, MapFlags, ProtFlags}, }; use std::ffi::c_void; -// TODO compile time flag -//pub const CMPLOG_MAP_W: usize = 65536; -pub const CMPLOG_MAP_W: usize = 8000; -pub const CMPLOG_MAP_H: usize = 32; -pub const CMPLOG_MAP_SIZE: usize = CMPLOG_MAP_W * CMPLOG_MAP_H; - -pub const CMPLOG_KIND_INS: u8 = 0; -pub const CMPLOG_KIND_RTN: u8 = 1; - extern crate libafl_targets; extern "C" { - pub fn __sanitizer_cov_trace_cmp8(arg1: u64, arg2: u64); + pub fn libafl_targets_cmplog_wrapper(k: u64, shape: u8, arg1: u64, arg2: u64); } -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct CmpLogHeader { - hits: u16, - shape: u8, - kind: u8, -} +// #[repr(C)] +// #[derive(Debug, Clone, Copy)] +// pub struct CmpLogHeader { +// hits: u16, +// shape: u8, +// kind: u8, +// } -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct CmpLogOperands(u64, u64); +// #[repr(C)] +// #[derive(Debug, Clone, Copy)] +// pub struct CmpLogOperands(u64, u64); -#[repr(C)] -#[derive(Debug, Clone, Copy)] -pub struct CmpLogMap { - headers: [CmpLogHeader; CMPLOG_MAP_W], - operands: [CmpLogOperands; CMPLOG_MAP_W], -} +// #[repr(C)] +// #[derive(Debug, Clone, Copy)] +// pub struct CmpLogMap { +// headers: [CmpLogHeader; CMPLOG_MAP_W], +// operands: [CmpLogOperands; CMPLOG_MAP_W], +// } -#[no_mangle] -pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { - headers: [CmpLogHeader { - hits: 0, - shape: 0, - kind: 0, - }; CMPLOG_MAP_W], - operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], -}; - -pub use libafl_cmplog_map as CMPLOG_MAP; - -#[no_mangle] -pub static mut libafl_cmplog_enabled: u8 = 0; - -pub use libafl_cmplog_enabled as CMPLOG_ENABLED; +// #[no_mangle] +// pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { +// headers: [CmpLogHeader { +// hits: 0, +// shape: 0, +// kind: 0, +// }; CMPLOG_MAP_W], +// operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], +// }; pub struct CmpLogRuntime { - regs: [u64; 2], - cmp_idx: usize, - cmplog_map: CmpLogMap, + regs: [u64; 3], + // cmp_idx: usize, + // cmplog_map: CmpLogMap, ops_save_register_and_blr_to_populate: Option>, } impl CmpLogRuntime { pub fn new() -> CmpLogRuntime { Self { - regs: [0; 2], - cmp_idx: 0, - cmplog_map: CmpLogMap { - headers: [CmpLogHeader { - hits: 0, - shape: 0, - kind: 0, - }; CMPLOG_MAP_W], - operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], - }, + regs: [0; 3], + // cmp_idx: 0, + // cmplog_map: CmpLogMap { + // headers: [CmpLogHeader { + // hits: 0, + // shape: 0, + // kind: 0, + // }; CMPLOG_MAP_W], + // operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], + // }, ops_save_register_and_blr_to_populate: None, } } @@ -82,18 +69,33 @@ impl CmpLogRuntime { extern "C" fn populate_lists(&mut self) { let op1 = self.regs[0]; let op2 = self.regs[1]; + let retaddr = self.regs[2]; - self.cmplog_map.headers[self.cmp_idx].hits += 1; - self.cmplog_map.headers[self.cmp_idx].shape = 8; - let cmplog_ops: CmpLogOperands = CmpLogOperands(op1, op2); - self.cmplog_map.operands[self.cmp_idx] = cmplog_ops; - self.cmp_idx += 1; + println!( + "entered populate_lists with: {:#02x}, {:#02x}, {:#02x}", + op1, op2, retaddr + ); + let mut k = (retaddr >> 4) ^ (retaddr << 8); + + k = k & ((CMPLOG_MAP_W as u64) - 1); + + unsafe { + libafl_targets_cmplog_wrapper(k, 8, op1, op2); + } + + println!("returned from c code"); + + // self.cmplog_map.headers[self.cmp_idx].hits += 1; + // self.cmplog_map.headers[self.cmp_idx].shape = 8; + // let cmplog_ops: CmpLogOperands = CmpLogOperands(op1, op2); + // self.cmplog_map.operands[self.cmp_idx] = cmplog_ops; + // self.cmp_idx += 1; } /// Generate the instrumentation blobs for the current arch. fn generate_instrumentation_blobs(&mut self) { macro_rules! blr_to_populate { - ($ops:ident, $bit:expr) => {dynasm!($ops + ($ops:ident) => {dynasm!($ops ; .arch aarch64 ; stp x2, x3, [sp, #-0x10]! ; stp x4, x5, [sp, #-0x10]! @@ -102,28 +104,17 @@ impl CmpLogRuntime { ; stp x10, x11, [sp, #-0x10]! ; stp x12, x13, [sp, #-0x10]! ; stp x14, x15, [sp, #-0x10]! - ; stp x16, x17, [sp, #-0x10]! - ; stp x18, x19, [sp, #-0x10]! - ; stp x20, x21, [sp, #-0x10]! - ; stp x22, x23, [sp, #-0x10]! - ; stp x24, x25, [sp, #-0x10]! - ; stp x26, x27, [sp, #-0x10]! - ; stp x28, x29, [sp, #-0x10]! - ; stp x30, xzr, [sp, #-0x10]! + ; stp x29, x30, [sp, #-0x10]! // jump to rust based population of the lists - // ; ldr x2, >self_regs_addr - // ; stp x0, x1, [x2] - // jump to c implementation of cmplog pupolation - ; ldr x2, >populate_lists - ; blr x2 - ; ldp x30, xzr, [sp], #0x10 - ; ldp x28, x29, [sp], #0x10 - ; ldp x26, x27, [sp], #0x10 - ; ldp x24, x25, [sp], #0x10 - ; ldp x22, x23, [sp], #0x10 - ; ldp x20, x21, [sp], #0x10 - ; ldp x18, x19, [sp], #0x10 - ; ldp x16, x17, [sp], #0x10 + ; ldr x5, >self_regs_addr + ; stp x0, x1, [x5] + ; adr x2, >done + ; str x2, [x5, 0x10] + ; ldr x4, >populate_lists + ; ldr x0, >self_addr + ; blr x4 + // restore the reg state before returning to the caller + ; ldp x29, x30, [sp], #0x10 ; ldp x14, x15, [sp], #0x10 ; ldp x12, x13, [sp], #0x10 ; ldp x10, x11, [sp], #0x10 @@ -132,17 +123,20 @@ impl CmpLogRuntime { ; ldp x4, x5, [sp], #0x10 ; ldp x2, x3, [sp], #0x10 ; b >done + ; self_addr: + ; .qword self as *mut _ as *mut c_void as i64 ; self_regs_addr: //for rust based population of the lists.. ; .qword &mut self.regs as *mut _ as *mut c_void as i64 ; populate_lists: - ; .qword __sanitizer_cov_trace_cmp8 as *mut c_void as i64 + //; .qword __sanitizer_cov_trace_cmp8 as *mut c_void as i64 + ; .qword CmpLogRuntime::populate_lists as *mut c_void as i64 ; done: );}; } let mut ops_save_register_and_blr_to_populate = dynasmrt::VecAssembler::::new(0); - blr_to_populate!(ops_save_register_and_blr_to_populate, 0); + blr_to_populate!(ops_save_register_and_blr_to_populate); self.ops_save_register_and_blr_to_populate = Some( ops_save_register_and_blr_to_populate diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index de795b4e45..3720878fcd 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -96,6 +96,12 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { } +#ifdef SANCOV_CMPLOG +void libafl_targets_cmplog_wrapper(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2){ + return __libafl_targets_cmplog(k, shape, arg1, arg2); +} +#endif + void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { uintptr_t rt = RETADDR; From ea5aba220c28be920d42aff4e986358bcafc8d03 Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 6 Jun 2021 12:53:24 +0300 Subject: [PATCH 30/43] change magic to 8 bytes --- fuzzers/frida_libpng/harness.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index 808e66113a..4496f2495f 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -113,7 +113,11 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { data[11] == 0xCD && data[12] == 0xEF && data[13] == 0xAA && - data[14] == 0xBB ) { + data[14] == 0x8F && + data[15] == 0x13 && + data[16] == 0x24 && + data[17] == 0xAA && + data[18] == 0xBB ) { printf("passed the test!"); } else { printf("x"); From 0a5aa77cd649976d4749cd51554722c96553b10b Mon Sep 17 00:00:00 2001 From: Omree Date: Sun, 6 Jun 2021 13:03:11 +0300 Subject: [PATCH 31/43] cmplog runs with observer- no crashes --- fuzzers/frida_libpng/src/fuzzer.rs | 26 +++++++++++++++++++++---- fuzzers/libfuzzer_stb_image/src/main.rs | 4 +++- libafl_targets/src/cmplog.h | 2 +- libafl_targets/src/cmplog.rs | 2 +- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index 3fb03f922a..6e32f5d417 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -32,7 +32,8 @@ use libafl::{ token_mutations::Tokens, }, observers::{HitcountsMapObserver, ObserversTuple, StdMapObserver, TimeObserver}, - stages::mutational::StdMutationalStage, + //stages::mutational::StdMutationalStage, + stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, HasMetadata, StdState}, stats::MultiStats, Error, @@ -302,7 +303,7 @@ unsafe fn fuzz( unsafe extern "C" fn(data: *const u8, size: usize) -> i32, > = lib.get(symbol_name.as_bytes()).unwrap(); - let mut frida_harness = move |input: &BytesInput| { + let mut frida_harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target.as_slice(); (target_func)(buf.as_ptr(), buf.len()); @@ -383,7 +384,6 @@ unsafe fn fuzz( // Setup a basic mutator with a mutational stage let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // A minimization+queue policy to get testcasess from the corpus let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); @@ -400,7 +400,6 @@ unsafe fn fuzz( tuple_list!( edges_observer, time_observer, - cmplog_observer, AsanErrorsObserver::new(&ASAN_ERRORS) ), &mut fuzzer, @@ -419,6 +418,25 @@ unsafe fn fuzz( println!("We imported {} inputs from disk.", state.corpus().count()); } + // Secondary harness due to mut ownership + let mut frida_harness = |input: &BytesInput| { + let target = input.target_bytes(); + let buf = target.as_slice(); + (target_func)(buf.as_ptr(), buf.len()); + ExitKind::Ok + }; + + // Setup a tracing stage in which we log comparisons + let tracing = TracingStage::new(InProcessExecutor::new( + &mut frida_harness, + tuple_list!(cmplog_observer), + &mut fuzzer, + &mut state, + &mut mgr, + )?); + + let mut stages = tuple_list!(tracing, StdMutationalStage::new(mutator)); + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; Ok(()) }; diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index 5fca306e93..4ee16c36c3 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -155,7 +155,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re } // Secondary harness due to mut ownership - let mut harness = |buf: &[u8]| { + let mut harness = |input: &BytesInput| { + let target = input.target_bytes(); + let buf = target.as_slice(); libfuzzer_test_one_input(buf); ExitKind::Ok }; diff --git a/libafl_targets/src/cmplog.h b/libafl_targets/src/cmplog.h index b595033602..5933f59c8f 100644 --- a/libafl_targets/src/cmplog.h +++ b/libafl_targets/src/cmplog.h @@ -33,7 +33,7 @@ extern uint8_t libafl_cmplog_enabled; static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { - if (!libafl_cmplog_enabled) return; + //if (!libafl_cmplog_enabled) return; uint16_t hits; if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) { diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index 8f975c716f..a02a57a575 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -140,7 +140,7 @@ pub use libafl_cmplog_map as CMPLOG_MAP; /// Value indicating if cmplog is enabled. #[no_mangle] -pub static mut libafl_cmplog_enabled: u8 = 0; +pub static mut libafl_cmplog_enabled: u8 = 1; pub use libafl_cmplog_enabled as CMPLOG_ENABLED; From 0d0bcc1796148eeaa70c4383004e20d9f695576e Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Mon, 7 Jun 2021 01:44:07 +0200 Subject: [PATCH 32/43] clippy fixes --- libafl/src/feedbacks/mod.rs | 5 +++-- libafl_frida/src/asan_errors.rs | 1 + libafl_frida/src/asan_rt.rs | 8 +++----- libafl_frida/src/cmplog_rt.rs | 10 +++++++++- libafl_frida/src/lib.rs | 3 ++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 2103a894cb..62aa6e5ab2 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -244,6 +244,7 @@ where OT: ObserversTuple; #[cfg(feature = "introspection")] + #[allow(clippy::too_many_arguments)] fn is_pair_interesting_with_perf( first: &mut A, second: &mut B, @@ -499,7 +500,7 @@ where OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; - if a == false { + if !a { return Ok(false); } @@ -533,7 +534,7 @@ where feedback_index, )?; - if a == false { + if !a { return Ok(false); } diff --git a/libafl_frida/src/asan_errors.rs b/libafl_frida/src/asan_errors.rs index 5d962d291e..bfa10abdae 100644 --- a/libafl_frida/src/asan_errors.rs +++ b/libafl_frida/src/asan_errors.rs @@ -102,6 +102,7 @@ impl AsanErrors { } /// Get a mutable reference to the global [`AsanErrors`] object + #[must_use] pub fn get_mut<'a>() -> &'a mut Self { unsafe { ASAN_ERRORS.as_mut().unwrap() } } diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index 94e6c74736..5eea8c94e3 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -174,11 +174,9 @@ impl AsanRuntime { /// real address, the stalked address is returned. #[must_use] pub fn real_address_for_stalked(&self, stalked: usize) -> usize { - if let Some(addr) = self.stalked_addresses.get(&stalked) { - *addr - } else { - stalked - } + self.stalked_addresses + .get(&stalked) + .map_or(stalked, |addr| *addr) } /// Unpoison all the memory that is currently mapped with read/write permissions. diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 8db1f32602..26ee44196b 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -55,6 +55,7 @@ pub struct CmpLogRuntime { } impl CmpLogRuntime { + #[must_use] pub fn new() -> CmpLogRuntime { Self { regs: [0; 3], @@ -82,7 +83,7 @@ impl CmpLogRuntime { ); let mut k = (retaddr >> 4) ^ (retaddr << 8); - k = k & ((CMPLOG_MAP_W as u64) - 1); + k &= (CMPLOG_MAP_W as u64) - 1; unsafe { libafl_targets_cmplog_wrapper(k, 8, op1, op2); @@ -180,7 +181,14 @@ impl CmpLogRuntime { /// Get the blob which saves the context, jumps to the populate function and restores the context #[inline] + #[must_use] pub fn ops_save_register_and_blr_to_populate(&self) -> &[u8] { self.ops_save_register_and_blr_to_populate.as_ref().unwrap() } } + +impl Default for CmpLogRuntime { + fn default() -> Self { + Self::new() + } +} diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 876a8713c1..bf94096f55 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -152,7 +152,8 @@ impl FridaOptions { self.enable_drcov } - /// Is CmpLog enabled? + /// Is `CmpLog` enabled? + #[must_use] #[inline] pub fn cmplog_enabled(&self) -> bool { self.enable_cmplog From 6f98bbe6cf5e4a6b6c55ccb25a389a83bac5718d Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 12:01:39 +0300 Subject: [PATCH 33/43] add cmplog_runtime as feature --- fuzzers/frida_libpng/Cargo.toml | 2 +- libafl_frida/Cargo.toml | 5 +++++ libafl_frida/src/helper.rs | 16 +++++++++++----- libafl_frida/src/lib.rs | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index cf4dbb83be..a411002168 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -24,7 +24,7 @@ which = "4.1" libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} capstone = "0.8.0" frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } -libafl_frida = { path = "../../libafl_frida", version = "0.3.2" } +libafl_frida = { path = "../../libafl_frida", version = "0.3.2", features = ["cmplog_runtime"] } libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] } lazy_static = "1.4.0" libc = "0.2" diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index f173c89b5b..3d4784f6b0 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -10,6 +10,11 @@ license = "MIT OR Apache-2.0" keywords = ["fuzzing", "frida", "instrumentation"] edition = "2018" + +[features] +default = [] +cmplog_runtime = [] + [build-dependencies] cc = { version = "1.0", features = ["parallel"] } diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index d3d5c00d80..f94ba4e79a 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -33,8 +33,12 @@ use rangemap::RangeMap; use nix::sys::mman::{mmap, MapFlags, ProtFlags}; -use crate::{asan_rt::AsanRuntime, cmplog_rt::CmpLogRuntime, FridaOptions}; +use crate::{asan_rt::AsanRuntime, FridaOptions}; +#[cfg(feature = "cmplog_runtime")] +use crate::cmplog_rt::CmpLogRuntime; + +#[cfg(feature = "cmplog_runtime")] enum CmplogOperandType { Regid(capstone::RegId), Imm(u64), @@ -85,6 +89,7 @@ pub struct FridaInstrumentationHelper<'a> { #[cfg(target_arch = "aarch64")] capstone: Capstone, asan_runtime: AsanRuntime, + #[cfg(all(feature = "cmplog_runtime"))] cmplog_runtime: CmpLogRuntime, ranges: RangeMap, module_map: ModuleMap, @@ -271,6 +276,7 @@ impl<'a> FridaInstrumentationHelper<'a> { .build() .expect("Failed to create Capstone object"), asan_runtime: AsanRuntime::new(options.clone()), + #[cfg(all(feature = "cmplog_runtime"))] cmplog_runtime: CmpLogRuntime::new(), ranges: RangeMap::new(), module_map: ModuleMap::new_from_names(modules_to_instrument), @@ -348,11 +354,10 @@ impl<'a> FridaInstrumentationHelper<'a> { ); } } - if helper.options().cmplog_enabled() { #[cfg(not(target_arch = "aarch64"))] todo!("Implement cmplog for non-aarch64 targets"); - #[cfg(target_arch = "aarch64")] + #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] // check if this instruction is a compare instruction and if so save the registers values if let Ok((op1, op2)) = helper.is_interesting_cmplog_instruction(address, instr) @@ -377,6 +382,7 @@ impl<'a> FridaInstrumentationHelper<'a> { if helper.options().asan_enabled() || helper.options().drcov_enabled() { helper.asan_runtime.init(gum, modules_to_instrument); } + #[cfg(all(feature = "cmplog_runtime"))] if helper.options.cmplog_enabled() { helper.cmplog_runtime.init(); } @@ -395,7 +401,7 @@ impl<'a> FridaInstrumentationHelper<'a> { Aarch64Register::from_u32(regint as u32).unwrap() } - #[cfg(target_arch = "aarch64")] + #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] #[inline] fn emit_comparison_handling( &self, @@ -1027,7 +1033,7 @@ impl<'a> FridaInstrumentationHelper<'a> { Err(()) } - #[cfg(target_arch = "aarch64")] + #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] #[inline] fn is_interesting_cmplog_instruction( &self, diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index bf94096f55..a459944881 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -10,6 +10,7 @@ pub mod asan_errors; /// The frida address sanitizer runtime pub mod asan_rt; +#[cfg(all(feature = "cmplog_runtime"))] /// The frida cmplog runtime pub mod cmplog_rt; From e8295988f2d3a9f01388bb3dbcbab8446d0af6ca Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 12:01:55 +0300 Subject: [PATCH 34/43] set cmplog command-line argument to false by default --- libafl_frida/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index a459944881..70668662d9 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -206,7 +206,7 @@ impl Default for FridaOptions { enable_coverage: true, enable_drcov: false, instrument_suppress_locations: None, - enable_cmplog: true, + enable_cmplog: false, } } } From 2451302575636790acc44c0d7301d116bab3009a Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 12:03:57 +0300 Subject: [PATCH 35/43] setup cmplog observer and mutator correctly --- fuzzers/frida_libpng/src/fuzzer.rs | 67 +++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index 37e8881490..fbf5857e01 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -29,6 +29,7 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes, Input}, mutators::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, + token_mutations::I2SRandReplace, token_mutations::Tokens, }, observers::{HitcountsMapObserver, ObserversTuple, StdMapObserver, TimeObserver}, @@ -417,26 +418,54 @@ unsafe fn fuzz( println!("We imported {} inputs from disk.", state.corpus().count()); } - // Secondary harness due to mut ownership - let mut frida_harness = |input: &BytesInput| { - let target = input.target_bytes(); - let buf = target.as_slice(); - (target_func)(buf.as_ptr(), buf.len()); - ExitKind::Ok + if frida_options.cmplog_enabled() { + // Secondary harness due to mut ownership + let mut frida_harness = |input: &BytesInput| { + let target = input.target_bytes(); + let buf = target.as_slice(); + (target_func)(buf.as_ptr(), buf.len()); + ExitKind::Ok + }; + + // Secondary helper due to mut ownership + let mut frida_helper = FridaInstrumentationHelper::new( + &gum, + &frida_options, + module_name, + &modules_to_instrument, + ); + + // Setup a tracing stage in which we log comparisons + let tracing = TracingStage::new(FridaInProcessExecutor::new( + &gum, + InProcessExecutor::new( + &mut frida_harness, + tuple_list!(cmplog_observer, AsanErrorsObserver::new(&ASAN_ERRORS)), + &mut fuzzer, + &mut state, + &mut mgr, + )?, + &mut frida_helper, + Duration::new(10, 0), + )); + + // Setup a randomic Input2State stage + let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!( + I2SRandReplace::new() + ))); + + // Setup a basic mutator + let mutational = StdMutationalStage::new(mutator); + + // The order of the stages matter! + let mut stages = tuple_list!(tracing, i2s, mutational); + + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; + } else { + let mut stages = tuple_list!(StdMutationalStage::new(mutator)); + + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; }; - - // Setup a tracing stage in which we log comparisons - let tracing = TracingStage::new(InProcessExecutor::new( - &mut frida_harness, - tuple_list!(cmplog_observer), - &mut fuzzer, - &mut state, - &mut mgr, - )?); - - let mut stages = tuple_list!(tracing, StdMutationalStage::new(mutator)); - - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; Ok(()) }; From 584b034a528cd8f4db8c653dc73466d664fa9666 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 12:05:35 +0300 Subject: [PATCH 36/43] decrease emitted code opcode count --- libafl_frida/src/cmplog_rt.rs | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 26ee44196b..45518f7eb5 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -72,15 +72,11 @@ impl CmpLogRuntime { } } - extern "C" fn populate_lists(&mut self) { - let op1 = self.regs[0]; - let op2 = self.regs[1]; - let retaddr = self.regs[2]; - - println!( - "entered populate_lists with: {:#02x}, {:#02x}, {:#02x}", - op1, op2, retaddr - ); + extern "C" fn populate_lists(&mut self, op1: u64, op2: u64, retaddr: u64) { + // println!( + // "entered populate_lists with: {:#02x}, {:#02x}, {:#02x}", + // op1, op2, retaddr + // ); let mut k = (retaddr >> 4) ^ (retaddr << 8); k &= (CMPLOG_MAP_W as u64) - 1; @@ -88,14 +84,6 @@ impl CmpLogRuntime { unsafe { libafl_targets_cmplog_wrapper(k, 8, op1, op2); } - - println!("returned from c code"); - - // self.cmplog_map.headers[self.cmp_idx].hits += 1; - // self.cmplog_map.headers[self.cmp_idx].shape = 8; - // let cmplog_ops: CmpLogOperands = CmpLogOperands(op1, op2); - // self.cmplog_map.operands[self.cmp_idx] = cmplog_ops; - // self.cmp_idx += 1; } /// Generate the instrumentation blobs for the current arch. @@ -112,10 +100,8 @@ impl CmpLogRuntime { ; stp x14, x15, [sp, #-0x10]! ; stp x29, x30, [sp, #-0x10]! // jump to rust based population of the lists - ; ldr x5, >self_regs_addr - ; stp x0, x1, [x5] - ; adr x2, >done - ; str x2, [x5, 0x10] + ; mov x2, x0 + ; adr x3, >done ; ldr x4, >populate_lists ; ldr x0, >self_addr ; blr x4 From 1fc9796bdbc0db32a69e7da419cd531130479003 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 12:06:31 +0300 Subject: [PATCH 37/43] add cmplog testing to the harness --- fuzzers/frida_libpng/harness.cc | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index 4496f2495f..15e9d430c4 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -109,19 +109,8 @@ void func1() { // http://www.libpng.org/pub/png/book/chapter13.html extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - if(data[10] == 0xAB && - data[11] == 0xCD && - data[12] == 0xEF && - data[13] == 0xAA && - data[14] == 0x8F && - data[15] == 0x13 && - data[16] == 0x24 && - data[17] == 0xAA && - data[18] == 0xBB ) { - printf("passed the test!"); - } else { - printf("x"); - return 0; + if (size >= 8 && *(uint64_t*)data == 0xABCDEFAA8F1324AA){ + abort(); } From 0e2a280eae523fdc0af238bdb92c67cfee9bd76a Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 13:01:22 +0300 Subject: [PATCH 38/43] get rid of irrelevant changes and unused code, add comments, change feature name to "cmplog" --- Cargo.toml | 5 +- fuzzers/frida_libpng/Cargo.toml | 2 +- fuzzers/frida_libpng/src/fuzzer.rs | 1 - fuzzers/libfuzzer_stb_image/src/main.rs | 3 - libafl_frida/Cargo.toml | 2 +- libafl_frida/src/cmplog_rt.rs | 83 +------------------------ libafl_frida/src/helper.rs | 31 ++++----- libafl_frida/src/lib.rs | 6 +- libafl_targets/src/cmplog.h | 2 +- libafl_targets/src/cmplog.rs | 2 +- 10 files changed, 30 insertions(+), 107 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 270994e82e..e78c01cd43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,14 +11,15 @@ members = [ "libafl_cc", "libafl_targets", "libafl_frida", - "libafl_tests", + "libafl_tests", ] default-members = [ "libafl", "libafl_derive", "libafl_cc", "libafl_targets", + "libafl_tests", ] exclude = [ - "fuzzers" + "fuzzers", ] diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index a411002168..cd4a2ee65c 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -24,7 +24,7 @@ which = "4.1" libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} capstone = "0.8.0" frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } -libafl_frida = { path = "../../libafl_frida", version = "0.3.2", features = ["cmplog_runtime"] } +libafl_frida = { path = "../../libafl_frida", version = "0.3.2", features = ["cmplog"] } libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] } lazy_static = "1.4.0" libc = "0.2" diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index fbf5857e01..a6f96c02eb 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -33,7 +33,6 @@ use libafl::{ token_mutations::Tokens, }, observers::{HitcountsMapObserver, ObserversTuple, StdMapObserver, TimeObserver}, - //stages::mutational::StdMutationalStage, stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, HasMetadata, StdState}, stats::MultiStats, diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index 4ee16c36c3..c718b1ad2e 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -75,9 +75,6 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - let cmplog = unsafe { &mut CMPLOG_MAP }; - let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. let feedback_state = MapFeedbackState::with_observer(&edges_observer); diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index 3d4784f6b0..b8871b08de 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -13,7 +13,7 @@ edition = "2018" [features] default = [] -cmplog_runtime = [] +cmplog = [] [build-dependencies] cc = { version = "1.0", features = ["parallel"] } diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 45518f7eb5..95b2193dd0 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -1,11 +1,5 @@ use dynasmrt::{dynasm, DynasmApi, DynasmLabelApi}; -use libafl_targets::cmplog::{ - libafl_cmplog_map, CmpLogHeader, CmpLogMap, CmpLogOperands, CMPLOG_MAP_W, -}; -use nix::{ - libc::{memmove, memset}, - sys::mman::{mmap, MapFlags, ProtFlags}, -}; +use libafl_targets::cmplog::CMPLOG_MAP_W; use std::ffi::c_void; extern crate libafl_targets; @@ -13,44 +7,7 @@ extern "C" { pub fn libafl_targets_cmplog_wrapper(k: u64, shape: u8, arg1: u64, arg2: u64); } -#[cfg(any(target_os = "macos", target_os = "ios"))] -const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANON; -#[cfg(not(any(target_os = "macos", target_os = "ios")))] -const ANONYMOUS_FLAG: MapFlags = MapFlags::MAP_ANONYMOUS; - -// #[repr(C)] -// #[derive(Debug, Clone, Copy)] -// pub struct CmpLogHeader { -// hits: u16, -// shape: u8, -// kind: u8, -// } - -// #[repr(C)] -// #[derive(Debug, Clone, Copy)] -// pub struct CmpLogOperands(u64, u64); - -// #[repr(C)] -// #[derive(Debug, Clone, Copy)] -// pub struct CmpLogMap { -// headers: [CmpLogHeader; CMPLOG_MAP_W], -// operands: [CmpLogOperands; CMPLOG_MAP_W], -// } - -// #[no_mangle] -// pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap { -// headers: [CmpLogHeader { -// hits: 0, -// shape: 0, -// kind: 0, -// }; CMPLOG_MAP_W], -// operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], -// }; - pub struct CmpLogRuntime { - regs: [u64; 3], - // cmp_idx: usize, - // cmplog_map: CmpLogMap, ops_save_register_and_blr_to_populate: Option>, } @@ -58,20 +15,11 @@ impl CmpLogRuntime { #[must_use] pub fn new() -> CmpLogRuntime { Self { - regs: [0; 3], - // cmp_idx: 0, - // cmplog_map: CmpLogMap { - // headers: [CmpLogHeader { - // hits: 0, - // shape: 0, - // kind: 0, - // }; CMPLOG_MAP_W], - // operands: [CmpLogOperands(0, 0); CMPLOG_MAP_W], - // }, ops_save_register_and_blr_to_populate: None, } } + /// Call the external function that populates the cmplog_map with the relevant values extern "C" fn populate_lists(&mut self, op1: u64, op2: u64, retaddr: u64) { // println!( // "entered populate_lists with: {:#02x}, {:#02x}, {:#02x}", @@ -117,10 +65,7 @@ impl CmpLogRuntime { ; b >done ; self_addr: ; .qword self as *mut _ as *mut c_void as i64 - ; self_regs_addr: //for rust based population of the lists.. - ; .qword &mut self.regs as *mut _ as *mut c_void as i64 ; populate_lists: - //; .qword __sanitizer_cov_trace_cmp8 as *mut c_void as i64 ; .qword CmpLogRuntime::populate_lists as *mut c_void as i64 ; done: );}; @@ -138,30 +83,6 @@ impl CmpLogRuntime { ); } pub fn init(&mut self) { - // workaround frida's frida-gum-allocate-near bug: - unsafe { - for _ in 0..64 { - mmap( - std::ptr::null_mut(), - 128 * 1024, - ProtFlags::PROT_NONE, - ANONYMOUS_FLAG | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .expect("Failed to map dummy regions for frida workaround"); - mmap( - std::ptr::null_mut(), - 4 * 1024 * 1024, - ProtFlags::PROT_NONE, - ANONYMOUS_FLAG | MapFlags::MAP_PRIVATE, - -1, - 0, - ) - .expect("Failed to map dummy regions for frida workaround"); - } - } - self.generate_instrumentation_blobs(); } diff --git a/libafl_frida/src/helper.rs b/libafl_frida/src/helper.rs index f94ba4e79a..adc5b1938b 100644 --- a/libafl_frida/src/helper.rs +++ b/libafl_frida/src/helper.rs @@ -35,10 +35,10 @@ use nix::sys::mman::{mmap, MapFlags, ProtFlags}; use crate::{asan_rt::AsanRuntime, FridaOptions}; -#[cfg(feature = "cmplog_runtime")] +#[cfg(feature = "cmplog")] use crate::cmplog_rt::CmpLogRuntime; -#[cfg(feature = "cmplog_runtime")] +#[cfg(feature = "cmplog")] enum CmplogOperandType { Regid(capstone::RegId), Imm(u64), @@ -89,7 +89,7 @@ pub struct FridaInstrumentationHelper<'a> { #[cfg(target_arch = "aarch64")] capstone: Capstone, asan_runtime: AsanRuntime, - #[cfg(all(feature = "cmplog_runtime"))] + #[cfg(feature = "cmplog")] cmplog_runtime: CmpLogRuntime, ranges: RangeMap, module_map: ModuleMap, @@ -276,7 +276,7 @@ impl<'a> FridaInstrumentationHelper<'a> { .build() .expect("Failed to create Capstone object"), asan_runtime: AsanRuntime::new(options.clone()), - #[cfg(all(feature = "cmplog_runtime"))] + #[cfg(feature = "cmplog")] cmplog_runtime: CmpLogRuntime::new(), ranges: RangeMap::new(), module_map: ModuleMap::new_from_names(modules_to_instrument), @@ -340,7 +340,7 @@ impl<'a> FridaInstrumentationHelper<'a> { todo!("Implement ASAN for non-aarch64 targets"); #[cfg(target_arch = "aarch64")] if let Ok((basereg, indexreg, displacement, width, shift, extender)) = - helper.is_interesting_asan_instruction(address, instr) + helper.asan_is_interesting_instruction(address, instr) { helper.emit_shadow_check( address, @@ -357,12 +357,11 @@ impl<'a> FridaInstrumentationHelper<'a> { if helper.options().cmplog_enabled() { #[cfg(not(target_arch = "aarch64"))] todo!("Implement cmplog for non-aarch64 targets"); - #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] + #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] // check if this instruction is a compare instruction and if so save the registers values if let Ok((op1, op2)) = - helper.is_interesting_cmplog_instruction(address, instr) + helper.cmplog_is_interesting_instruction(address, instr) { - println!("emmiting at {} => {}", address, instr); //emit code that saves the relevant data in runtime(passes it to x0, x1) helper.emit_comparison_handling(address, &output, op1, op2); } @@ -382,7 +381,7 @@ impl<'a> FridaInstrumentationHelper<'a> { if helper.options().asan_enabled() || helper.options().drcov_enabled() { helper.asan_runtime.init(gum, modules_to_instrument); } - #[cfg(all(feature = "cmplog_runtime"))] + #[cfg(feature = "cmplog")] if helper.options.cmplog_enabled() { helper.cmplog_runtime.init(); } @@ -401,8 +400,9 @@ impl<'a> FridaInstrumentationHelper<'a> { Aarch64Register::from_u32(regint as u32).unwrap() } - #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] + #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] #[inline] + /// Emit the instrumentation code which is responsible for opernads value extraction and cmplog map population fn emit_comparison_handling( &self, _address: u64, @@ -440,7 +440,7 @@ impl<'a> FridaInstrumentationHelper<'a> { } } } - CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { + CmplogOperandType::Mem(basereg, indexreg, displacement, _width) => { let basereg = self.writer_register(basereg); let indexreg = if indexreg.0 != 0 { Some(self.writer_register(indexreg)) @@ -509,7 +509,7 @@ impl<'a> FridaInstrumentationHelper<'a> { } } } - CmplogOperandType::Mem(basereg, indexreg, displacement, width) => { + CmplogOperandType::Mem(basereg, indexreg, displacement, _width) => { let basereg = self.writer_register(basereg); let indexreg = if indexreg.0 != 0 { Some(self.writer_register(indexreg)) @@ -983,7 +983,7 @@ impl<'a> FridaInstrumentationHelper<'a> { #[cfg(target_arch = "aarch64")] #[inline] - fn is_interesting_asan_instruction( + fn asan_is_interesting_instruction( &self, _address: u64, instr: &Insn, @@ -1033,9 +1033,10 @@ impl<'a> FridaInstrumentationHelper<'a> { Err(()) } - #[cfg(all(feature = "cmplog_runtime", target_arch = "aarch64"))] + #[cfg(all(feature = "cmplog", target_arch = "aarch64"))] #[inline] - fn is_interesting_cmplog_instruction( + /// Check if the current instruction is cmplog relevant one(any opcode which sets the flags) + fn cmplog_is_interesting_instruction( &self, _address: u64, instr: &Insn, diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 70668662d9..1b049e19b8 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -10,7 +10,7 @@ pub mod asan_errors; /// The frida address sanitizer runtime pub mod asan_rt; -#[cfg(all(feature = "cmplog_runtime"))] +#[cfg(feature = "cmplog")] /// The frida cmplog runtime pub mod cmplog_rt; @@ -108,6 +108,10 @@ impl FridaOptions { } "cmplog" => { options.enable_cmplog = value.parse().unwrap(); + match cfg!(feature = "cmplog") { + false => panic!("cmplog feature is disabled!"), + _ => (), + } } _ => { panic!("unknown FRIDA option: '{}'", option); diff --git a/libafl_targets/src/cmplog.h b/libafl_targets/src/cmplog.h index 5933f59c8f..b595033602 100644 --- a/libafl_targets/src/cmplog.h +++ b/libafl_targets/src/cmplog.h @@ -33,7 +33,7 @@ extern uint8_t libafl_cmplog_enabled; static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { - //if (!libafl_cmplog_enabled) return; + if (!libafl_cmplog_enabled) return; uint16_t hits; if (libafl_cmplog_map.headers[k].kind != CMPLOG_KIND_INS) { diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index a02a57a575..8f975c716f 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -140,7 +140,7 @@ pub use libafl_cmplog_map as CMPLOG_MAP; /// Value indicating if cmplog is enabled. #[no_mangle] -pub static mut libafl_cmplog_enabled: u8 = 1; +pub static mut libafl_cmplog_enabled: u8 = 0; pub use libafl_cmplog_enabled as CMPLOG_ENABLED; From 3651e6aedf9f81924d292db0362ccaabecbcc259 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 13:08:50 +0300 Subject: [PATCH 39/43] get rid of some unessecery whitespaces and new lines --- Cargo.toml | 2 +- fuzzers/frida_libpng/harness.cc | 222 ++++++++++++++++---------------- libafl_targets/src/cmplog.h | 2 - libafl_targets/src/cmplog.rs | 2 - libafl_targets/src/sancov_cmp.c | 5 - 5 files changed, 111 insertions(+), 122 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e78c01cd43..991821b677 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ members = [ "libafl_cc", "libafl_targets", "libafl_frida", - "libafl_tests", + "libafl_tests", ] default-members = [ "libafl", diff --git a/fuzzers/frida_libpng/harness.cc b/fuzzers/frida_libpng/harness.cc index 15e9d430c4..1ed473b50c 100644 --- a/fuzzers/frida_libpng/harness.cc +++ b/fuzzers/frida_libpng/harness.cc @@ -101,7 +101,7 @@ void func2() { } __attribute__((noinline)) void func1() { - //printf("func1\n"); + //printf("func1\n"); func2(); } // Entry point for LibFuzzer. @@ -112,120 +112,118 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size >= 8 && *(uint64_t*)data == 0xABCDEFAA8F1324AA){ abort(); } - - if (size < kPngHeaderSize) { - return 0; - } - - - func1(); - - std::vector v(data, data + size); - if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { - // not a PNG. - return 0; - } - - PngObjectHandler png_handler; - png_handler.png_ptr = nullptr; - png_handler.row_ptr = nullptr; - png_handler.info_ptr = nullptr; - png_handler.end_info_ptr = nullptr; - - png_handler.png_ptr = png_create_read_struct - (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_handler.png_ptr) { - return 0; - } - - png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); - if (!png_handler.info_ptr) { - PNG_CLEANUP - return 0; - } - - png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); - if (!png_handler.end_info_ptr) { - PNG_CLEANUP - return 0; - } - - png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); -#ifdef PNG_IGNORE_ADLER32 - png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); -#endif - - // Setting up reading from buffer. - png_handler.buf_state = new BufState(); - png_handler.buf_state->data = data + kPngHeaderSize; - png_handler.buf_state->bytes_left = size - kPngHeaderSize; - png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); - png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); - - if (setjmp(png_jmpbuf(png_handler.png_ptr))) { - PNG_CLEANUP - return 0; - } - - // Reading. - png_read_info(png_handler.png_ptr, png_handler.info_ptr); - - // reset error handler to put png_deleter into scope. - if (setjmp(png_jmpbuf(png_handler.png_ptr))) { - PNG_CLEANUP - return 0; - } - - png_uint_32 width, height; - int bit_depth, color_type, interlace_type, compression_type; - int filter_type; - - if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, - &height, &bit_depth, &color_type, &interlace_type, - &compression_type, &filter_type)) { - PNG_CLEANUP - return 0; - } - - // This is going to be too slow. - if (width && height > 100000000 / width) { - PNG_CLEANUP -#ifdef HAS_DUMMY_CRASH - #ifdef __aarch64__ - asm volatile (".word 0xf7f0a000\n"); - #else - asm("ud2"); - #endif -#endif - return 0; - } - - // Set several transforms that browsers typically use: - png_set_gray_to_rgb(png_handler.png_ptr); - png_set_expand(png_handler.png_ptr); - png_set_packing(png_handler.png_ptr); - png_set_scale_16(png_handler.png_ptr); - png_set_tRNS_to_alpha(png_handler.png_ptr); - - int passes = png_set_interlace_handling(png_handler.png_ptr); - - png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); - - png_handler.row_ptr = png_malloc( - png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, - png_handler.info_ptr)); - - for (int pass = 0; pass < passes; ++pass) { - for (png_uint_32 y = 0; y < height; ++y) { - png_read_row(png_handler.png_ptr, - static_cast(png_handler.row_ptr), nullptr); + return 0; } - } - png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); - PNG_CLEANUP - return 0; + func1(); + + std::vector v(data, data + size); + if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { + // not a PNG. + return 0; + } + + PngObjectHandler png_handler; + png_handler.png_ptr = nullptr; + png_handler.row_ptr = nullptr; + png_handler.info_ptr = nullptr; + png_handler.end_info_ptr = nullptr; + + png_handler.png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_handler.png_ptr) { + return 0; + } + + png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.info_ptr) { + PNG_CLEANUP + return 0; + } + + png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.end_info_ptr) { + PNG_CLEANUP + return 0; + } + + png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); +#ifdef PNG_IGNORE_ADLER32 + png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); +#endif + + // Setting up reading from buffer. + png_handler.buf_state = new BufState(); + png_handler.buf_state->data = data + kPngHeaderSize; + png_handler.buf_state->bytes_left = size - kPngHeaderSize; + png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); + png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); + + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + // Reading. + png_read_info(png_handler.png_ptr, png_handler.info_ptr); + + // reset error handler to put png_deleter into scope. + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type; + int filter_type; + + if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, + &height, &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type)) { + PNG_CLEANUP + return 0; + } + + // This is going to be too slow. + if (width && height > 100000000 / width) { + PNG_CLEANUP +#ifdef HAS_DUMMY_CRASH +#ifdef __aarch64__ + asm volatile (".word 0xf7f0a000\n"); +#else + asm("ud2"); +#endif +#endif + return 0; + } + + // Set several transforms that browsers typically use: + png_set_gray_to_rgb(png_handler.png_ptr); + png_set_expand(png_handler.png_ptr); + png_set_packing(png_handler.png_ptr); + png_set_scale_16(png_handler.png_ptr); + png_set_tRNS_to_alpha(png_handler.png_ptr); + + int passes = png_set_interlace_handling(png_handler.png_ptr); + + png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); + + png_handler.row_ptr = png_malloc( + png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, + png_handler.info_ptr)); + + for (int pass = 0; pass < passes; ++pass) { + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_handler.png_ptr, + static_cast(png_handler.row_ptr), nullptr); + } + } + + png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); + + PNG_CLEANUP + return 0; } diff --git a/libafl_targets/src/cmplog.h b/libafl_targets/src/cmplog.h index b595033602..762ed548d3 100644 --- a/libafl_targets/src/cmplog.h +++ b/libafl_targets/src/cmplog.h @@ -29,10 +29,8 @@ extern CmpLogMap libafl_cmplog_map; extern uint8_t libafl_cmplog_enabled; - static void __libafl_targets_cmplog(uintptr_t k, uint8_t shape, uint64_t arg1, uint64_t arg2) { - if (!libafl_cmplog_enabled) return; uint16_t hits; diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index 8f975c716f..77b7e2671c 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -201,7 +201,6 @@ where unsafe { CMPLOG_ENABLED = 0; } - if self.add_meta { self.add_cmpvalues_meta(state); } @@ -222,7 +221,6 @@ impl<'a> CmpLogObserver<'a> { Self { name: name.to_string(), size: None, - add_meta, map: OwnedRefMut::Ref(map), } diff --git a/libafl_targets/src/sancov_cmp.c b/libafl_targets/src/sancov_cmp.c index 8c0c1edb74..8e4075e871 100644 --- a/libafl_targets/src/sancov_cmp.c +++ b/libafl_targets/src/sancov_cmp.c @@ -13,7 +13,6 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); - #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; __libafl_targets_value_profile1(k, arg1, arg2); @@ -30,7 +29,6 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); - #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; __libafl_targets_value_profile2(k, arg1, arg2); @@ -47,7 +45,6 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); - #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; __libafl_targets_value_profile4(k, arg1, arg2); @@ -64,7 +61,6 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) { uintptr_t k = RETADDR; k = (k >> 4) ^ (k << 8); - #ifdef SANCOV_VALUE_PROFILE k &= MAP_SIZE - 1; __libafl_targets_value_profile8(k, arg1, arg2); @@ -116,7 +112,6 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) { #endif - } } From b8e4f4c6fa61ea43c6b619238c7445802670ffa5 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 13:16:05 +0300 Subject: [PATCH 40/43] fix clippy errors --- libafl_frida/src/cmplog_rt.rs | 2 +- libafl_frida/src/lib.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libafl_frida/src/cmplog_rt.rs b/libafl_frida/src/cmplog_rt.rs index 95b2193dd0..ab93bb67b1 100644 --- a/libafl_frida/src/cmplog_rt.rs +++ b/libafl_frida/src/cmplog_rt.rs @@ -19,7 +19,7 @@ impl CmpLogRuntime { } } - /// Call the external function that populates the cmplog_map with the relevant values + /// Call the external function that populates the `cmplog_map` with the relevant values extern "C" fn populate_lists(&mut self, op1: u64, op2: u64, retaddr: u64) { // println!( // "entered populate_lists with: {:#02x}, {:#02x}, {:#02x}", diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 1b049e19b8..31063c899b 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -108,9 +108,8 @@ impl FridaOptions { } "cmplog" => { options.enable_cmplog = value.parse().unwrap(); - match cfg!(feature = "cmplog") { - false => panic!("cmplog feature is disabled!"), - _ => (), + if !cfg!(feature = "cmplog") && options.enable_cmplog { + panic!("cmplog feature is disabled!") } } _ => { From ed26319a21479456c92ae50ab169278a8d74e1df Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 16:27:22 +0300 Subject: [PATCH 41/43] add cmplog_cores command line argument support --- libafl_frida/src/lib.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 31063c899b..def1b57437 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -17,7 +17,7 @@ pub mod cmplog_rt; /// The `LibAFL` firda helper pub mod helper; -// for parsing asan cores +// for parsing asan and cmplog cores use libafl::bolts::os::parse_core_bind_arg; // for getting current core_id use core_affinity::get_core_ids; @@ -47,6 +47,7 @@ impl FridaOptions { pub fn parse_env_options() -> Self { let mut options = Self::default(); let mut asan_cores = None; + let mut cmplog_cores = None; if let Ok(env_options) = std::env::var("LIBAFL_FRIDA_OPTIONS") { for option in env_options.trim().split(':') { @@ -108,10 +109,21 @@ impl FridaOptions { } "cmplog" => { options.enable_cmplog = value.parse().unwrap(); + + #[cfg(not(target_arch = "aarch64"))] + if options.enable_cmplog { + panic!( + "cmplog is not currently supported on targets other than aarch64" + ); + } + if !cfg!(feature = "cmplog") && options.enable_cmplog { panic!("cmplog feature is disabled!") } } + "cmplog_cores" => { + cmplog_cores = parse_core_bind_arg(value); + } _ => { panic!("unknown FRIDA option: '{}'", option); } @@ -124,14 +136,25 @@ impl FridaOptions { assert_eq!( core_ids.len(), 1, - "Client should only be enabled on one core" + "[asan_cores] Client should only be enabled on one core" ); let core_id = core_ids[0].id; options.enable_asan = asan_cores.contains(&core_id); } } + if options.enable_cmplog { + if let Some(cmplog_cores) = cmplog_cores { + let core_ids = get_core_ids().unwrap(); + assert_eq!( + core_ids.len(), + 1, + "[cmplog_cores] Client should only be enabled on one core" + ); + let core_id = core_ids[0].id; + options.enable_cmplog = cmplog_cores.contains(&core_id); + } + } } - options } From 1181728a4ffb619ebc54ceb8a5267dc97964d824 Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 16:55:42 +0300 Subject: [PATCH 42/43] changed command line parameter from cmplog_cores to cmplog-cores --- libafl_frida/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index def1b57437..8fcdc4745b 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -121,7 +121,7 @@ impl FridaOptions { panic!("cmplog feature is disabled!") } } - "cmplog_cores" => { + "cmplog-cores" => { cmplog_cores = parse_core_bind_arg(value); } _ => { From 48af1661b49ad4e3bfb858b39a9e4f4c23c9f16b Mon Sep 17 00:00:00 2001 From: Omree Date: Wed, 9 Jun 2021 17:20:26 +0300 Subject: [PATCH 43/43] change error message --- libafl_frida/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libafl_frida/src/lib.rs b/libafl_frida/src/lib.rs index 23a8978911..7ae5ba6962 100644 --- a/libafl_frida/src/lib.rs +++ b/libafl_frida/src/lib.rs @@ -135,7 +135,7 @@ impl FridaOptions { assert_eq!( core_ids.len(), 1, - "[asan_cores] Client should only be enabled on one core" + "Client should only be bound to a single core" ); let core_id = core_ids[0].id; options.enable_asan = asan_cores.contains(&core_id); @@ -147,7 +147,7 @@ impl FridaOptions { assert_eq!( core_ids.len(), 1, - "[cmplog_cores] Client should only be enabled on one core" + "Client should only be bound to a single core" ); let core_id = core_ids[0].id; options.enable_cmplog = cmplog_cores.contains(&core_id);