From bfa3fffc185e6e71239e7d2031cfb3ba84846714 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Wed, 5 May 2021 15:38:24 +0200 Subject: [PATCH] Observers lifetime (#89) * introduce MatchName and alow lifetimes in observers * adapt fuzzers to observers with lifetime * introduce type_eq when on nightly * fix no_std * fmt --- fuzzers/baby_fuzzer/src/main.rs | 15 ++--- fuzzers/frida_libpng/src/fuzzer.rs | 8 +-- fuzzers/libfuzzer_libmozjpeg/src/lib.rs | 11 ++-- fuzzers/libfuzzer_libpng/src/lib.rs | 14 +++-- fuzzers/libfuzzer_reachability/src/lib.rs | 59 ++++++------------ fuzzers/libfuzzer_stb_image/src/main.rs | 11 ++-- libafl/Cargo.toml | 3 +- libafl/build.rs | 18 ++++++ libafl/src/bolts/tuples.rs | 73 ++++++++++++++++++++++- libafl/src/events/mod.rs | 2 +- libafl/src/feedbacks/map.rs | 7 ++- libafl/src/feedbacks/mod.rs | 23 ++++--- libafl/src/lib.rs | 1 + libafl/src/observers/map.rs | 60 +++++++++---------- libafl/src/observers/mod.rs | 11 ++-- libafl_frida/src/asan_rt.rs | 6 +- 16 files changed, 193 insertions(+), 129 deletions(-) diff --git a/fuzzers/baby_fuzzer/src/main.rs b/fuzzers/baby_fuzzer/src/main.rs index e5f026fc42..730691115c 100644 --- a/fuzzers/baby_fuzzer/src/main.rs +++ b/fuzzers/baby_fuzzer/src/main.rs @@ -46,9 +46,8 @@ pub fn main() { // such as the notification of the addition of a new item to the corpus let mut mgr = SimpleEventManager::new(stats); - // Create an observation channel using the siganls map - let observer = - StdMapObserver::new("signals", unsafe { &mut SIGNALS }, unsafe { SIGNALS.len() }); + // Create an observation channel using the signals map + let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); // create a State from scratch let mut state = State::new( @@ -76,13 +75,9 @@ pub fn main() { let scheduler = QueueCorpusScheduler::new(); // Create the executor for an in-process function with just one observer - let mut executor = InProcessExecutor::new( - &mut harness, - tuple_list!(observer), - &mut state, - &mut mgr, - ) - .expect("Failed to create the Executor".into()); + let mut executor = + InProcessExecutor::new(&mut harness, tuple_list!(observer), &mut state, &mut mgr) + .expect("Failed to create the Executor".into()); // Generator of printable bytearrays of max size 32 let mut generator = RandPrintablesGenerator::new(32); diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index 5639dd73d8..90ccb91f6c 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -258,12 +258,8 @@ unsafe fn fuzz( }; let frida_options = FridaOptions::parse_env_options(); - let mut frida_helper = FridaInstrumentationHelper::new( - &gum, - &frida_options, - module_name, - &modules_to_instrument, - ); + let mut frida_helper = + FridaInstrumentationHelper::new(&gum, &frida_options, module_name, &modules_to_instrument); // Create an observation channel using the coverage map let edges_observer = HitcountsMapObserver::new(StdMapObserver::new_from_ptr( diff --git a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs index dd94e71205..4de98a3304 100644 --- a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs @@ -22,7 +22,7 @@ use libafl::{ }; use libafl_targets::{ - libfuzzer_initialize, libfuzzer_test_one_input, CMP_MAP, CMP_MAP_SIZE, EDGES_MAP, MAX_EDGES_NUM, + libfuzzer_initialize, libfuzzer_test_one_input, CMP_MAP, EDGES_MAP, MAX_EDGES_NUM, }; const ALLOC_MAP_SIZE: usize = 16 * 1024; @@ -59,15 +59,14 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> setup_restarting_mgr_std(stats, broker_port).expect("Failed to setup the restarter".into()); // Create an observation channel using the coverage map - let edges_observer = - StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM }); + let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; + let edges_observer = StdMapObserver::new("edges", edges); // Create an observation channel using the cmp map - let cmps_observer = StdMapObserver::new("cmps", unsafe { &mut CMP_MAP }, CMP_MAP_SIZE); + let cmps_observer = StdMapObserver::new("cmps", unsafe { &mut CMP_MAP }); // Create an observation channel using the allocations map - let allocs_observer = - StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map }, ALLOC_MAP_SIZE); + let allocs_observer = StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map }); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index 578c9287ad..7193951655 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -63,11 +63,13 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> } }, }; - + // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { - StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM) - }); + let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; + let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges)); + + // Create an observation channel to keep track of the execution time + let time_observer = TimeObserver::new("time"); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -79,7 +81,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Feedbacks to rate the interestingness of an input feedback_or!( MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), - TimeFeedback::new() + TimeFeedback::new_with_observer(&time_observer) ), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer @@ -122,7 +124,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> let mut executor = TimeoutExecutor::new( InProcessExecutor::new( &mut harness, - tuple_list!(edges_observer, TimeObserver::new("time")), + tuple_list!(edges_observer, time_observer), &mut state, &mut restarting_mgr, )?, diff --git a/fuzzers/libfuzzer_reachability/src/lib.rs b/fuzzers/libfuzzer_reachability/src/lib.rs index 13015a3bc4..79c2921bea 100644 --- a/fuzzers/libfuzzer_reachability/src/lib.rs +++ b/fuzzers/libfuzzer_reachability/src/lib.rs @@ -1,38 +1,28 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use core::time::Duration; use std::{env, path::PathBuf}; use libafl::{ bolts::tuples::tuple_list, - corpus::{ - Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, - QueueCorpusScheduler, - }, + corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler}, events::{setup_restarting_mgr_std, EventManager}, - executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, - feedback_or, - feedbacks::{ - CrashFeedback, MaxMapFeedback, ReachabilityFeedback, TimeFeedback, TimeoutFeedback, - }, + executors::{inprocess::InProcessExecutor, ExitKind}, + feedbacks::{MaxMapFeedback, ReachabilityFeedback}, fuzzer::{Fuzzer, StdFuzzer}, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::token_mutations::Tokens, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{HitcountsMapObserver, StdMapObserver}, stages::mutational::StdMutationalStage, state::{HasCorpus, HasMetadata, State}, stats::SimpleStats, utils::{current_nanos, StdRand}, Error, }; - use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; -#[cfg(unix)] const TARGET_SIZE: usize = 4; -#[cfg(unix)] extern "C" { static __libafl_target_list: *mut usize; } @@ -75,12 +65,12 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> }; // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { - StdMapObserver::new("edges", &mut EDGES_MAP, MAX_EDGES_NUM) - }); + let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; + let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges)); let reachability_observer = unsafe { StdMapObserver::new_from_ptr("png.c", __libafl_target_list, TARGET_SIZE) }; + // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { State::new( @@ -89,19 +79,12 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Corpus that will be evolved, we keep it in memory for performance InMemoryCorpus::new(), // Feedbacks to rate the interestingness of an input - feedback_or!( - MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), - TimeFeedback::new() - ), + MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // Feedbacks to recognize an input as solution - feedback_or!( - CrashFeedback::new(), - TimeoutFeedback::new(), - ReachabilityFeedback::new_with_observer(&reachability_observer) - ), + ReachabilityFeedback::new_with_observer(&reachability_observer), ) }); @@ -125,8 +108,8 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // A fuzzer with just one stage let mut fuzzer = StdFuzzer::new(tuple_list!(stage)); - // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); + // A random policy to get testcasess from the corpus + let scheduler = RandCorpusScheduler::new(); // The wrapped harness function, calling out to the LLVM-style harness let mut harness = |buf: &[u8]| { @@ -135,20 +118,12 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> }; // Create the executor for an in-process function with one observer for edge coverage and one for the execution time - let mut executor = TimeoutExecutor::new( - InProcessExecutor::new( - &mut harness, - tuple_list!( - edges_observer, - reachability_observer, - TimeObserver::new("time") - ), - &mut state, - &mut restarting_mgr, - )?, - // 10 seconds timeout - Duration::new(10, 0), - ); + let mut executor = InProcessExecutor::new( + &mut harness, + tuple_list!(edges_observer, reachability_observer,), + &mut state, + &mut restarting_mgr, + )?; // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index 3221034b8b..f9f3755e26 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -63,8 +63,11 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Create an observation channel using the coverage map // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) - let edges_observer = - StdMapObserver::new("edges", unsafe { &mut EDGES_MAP }, unsafe { MAX_EDGES_NUM }); + let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; + let edges_observer = StdMapObserver::new("edges", edges); + + // Create an observation channel to keep track of the execution time + let time_observer = TimeObserver::new("time"); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -76,7 +79,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Feedbacks to rate the interestingness of an input feedback_or!( MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), - TimeFeedback::new() + TimeFeedback::new_with_observer(&time_observer) ), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer @@ -118,7 +121,7 @@ fn fuzz(corpus_dirs: Vec, objective_dir: PathBuf, broker_port: u16) -> // Create the executor for an in-process function with just one observer for edge coverage let mut executor = InProcessExecutor::new( &mut harness, - tuple_list!(edges_observer, TimeObserver::new("time")), + tuple_list!(edges_observer, time_observer), &mut state, &mut restarting_mgr, )?; diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index b0296623b0..7b6616f8a9 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -10,7 +10,8 @@ keywords = ["fuzzing", "testing", "security"] edition = "2018" build = "build.rs" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[build-dependencies] +rustc_version = "0.3.3" [dev-dependencies] criterion = "0.3" # Benchmarking diff --git a/libafl/build.rs b/libafl/build.rs index f1bf264c6b..15a69aaa4e 100644 --- a/libafl/build.rs +++ b/libafl/build.rs @@ -1,5 +1,7 @@ //! special handling to build and link libafl +use rustc_version::{version_meta, Channel}; + fn main() { #[cfg(target_os = "windows")] windows::build!( @@ -9,4 +11,20 @@ fn main() { windows::win32::system_services::{CreateFileMappingA, OpenFileMappingA, MapViewOfFile, UnmapViewOfFile}, windows::win32::debug::{SetUnhandledExceptionFilter, EXCEPTION_POINTERS, EXCEPTION_RECORD, LPTOP_LEVEL_EXCEPTION_FILTER} ); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=RUSTC_IS_STABLE"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=RUSTC_IS_BETA"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=RUSTC_IS_NIGHTLY"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=RUSTC_IS_DEV"); + } + } } diff --git a/libafl/src/bolts/tuples.rs b/libafl/src/bolts/tuples.rs index 64ec061bc8..1e5d08fe14 100644 --- a/libafl/src/bolts/tuples.rs +++ b/libafl/src/bolts/tuples.rs @@ -6,6 +6,34 @@ use core::any::TypeId; use xxhash_rust::const_xxh3::xxh3_64; +#[cfg(feature = "RUSTC_IS_NIGHTLY")] +/// From https://stackoverflow.com/a/60138532/7658998 +const fn type_eq() -> bool { + // Helper trait. `VALUE` is false, except for the specialization of the + // case where `T == U`. + trait TypeEq { + const VALUE: bool; + } + + // Default implementation. + impl TypeEq for T { + default const VALUE: bool = false; + } + + // Specialization for `T == U`. + impl TypeEq for T { + const VALUE: bool = true; + } + + >::VALUE +} + +#[cfg(not(feature = "RUSTC_IS_NIGHTLY"))] +const fn type_eq() -> bool { + // BEWARE! This is not unsafe, it is SUPER UNSAFE + true +} + pub trait HasLen { const LEN: usize; @@ -60,7 +88,7 @@ impl HasNameIdTuple for () { impl HasNameIdTuple for (Head, Tail) where - Head: 'static + HasNameId, + Head: HasNameId, Tail: HasNameIdTuple, { fn get_const_name(&self, index: usize) -> Option<&'static str> { @@ -132,6 +160,7 @@ where Tail: MatchType, { fn match_type(&self, f: fn(t: &T)) { + // Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static if TypeId::of::() == TypeId::of::() { f(unsafe { (&self.0 as *const _ as *const T).as_ref() }.unwrap()); } @@ -139,6 +168,7 @@ where } fn match_type_mut(&mut self, f: fn(t: &mut T)) { + // Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static if TypeId::of::() == TypeId::of::() { f(unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() }.unwrap()); } @@ -164,7 +194,7 @@ impl NamedTuple for () { impl NamedTuple for (Head, Tail) where - Head: 'static + Named, + Head: Named, Tail: NamedTuple, { fn get_name(&self, index: usize) -> Option<&str> { @@ -176,6 +206,43 @@ where } } +/// This operation is unsafe with Rust stable, wait for https://stackoverflow.com/a/60138532/7658998 +pub trait MatchName { + fn match_name(&self, name: &str) -> Option<&T>; + fn match_name_mut(&mut self, name: &str) -> Option<&mut T>; +} + +impl MatchName for () { + fn match_name(&self, _name: &str) -> Option<&T> { + None + } + fn match_name_mut(&mut self, _name: &str) -> Option<&mut T> { + None + } +} + +impl MatchName for (Head, Tail) +where + Head: Named, + Tail: MatchName, +{ + fn match_name(&self, name: &str) -> Option<&T> { + if type_eq::() && name == self.0.name() { + unsafe { (&self.0 as *const _ as *const T).as_ref() } + } else { + self.1.match_name::(name) + } + } + + fn match_name_mut(&mut self, name: &str) -> Option<&mut T> { + if type_eq::() && name == self.0.name() { + unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() } + } else { + self.1.match_name_mut::(name) + } + } +} + pub trait MatchNameAndType { fn match_name_type(&self, name: &str) -> Option<&T>; fn match_name_type_mut(&mut self, name: &str) -> Option<&mut T>; @@ -196,6 +263,7 @@ where Tail: MatchNameAndType, { fn match_name_type(&self, name: &str) -> Option<&T> { + // Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static if TypeId::of::() == TypeId::of::() && name == self.0.name() { unsafe { (&self.0 as *const _ as *const T).as_ref() } } else { @@ -204,6 +272,7 @@ where } fn match_name_type_mut(&mut self, name: &str) -> Option<&mut T> { + // Switch this check to https://stackoverflow.com/a/60138532/7658998 when in stable and remove 'static if TypeId::of::() == TypeId::of::() && name == self.0.name() { unsafe { (&mut self.0 as *mut _ as *mut T).as_mut() } } else { diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index e332630d2f..6ab6924471 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -247,7 +247,7 @@ mod tests { #[test] fn test_event_serde() { - let obv = StdMapObserver::new("test", unsafe { &mut MAP }, unsafe { MAP.len() }); + let obv = StdMapObserver::new("test", unsafe { &mut MAP }); let map = tuple_list!(obv); let observers_buf = postcard::to_allocvec(&map).unwrap(); diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index cc76a6cf63..b940adc785 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -144,8 +144,8 @@ where OT: ObserversTuple, { let mut interesting = false; - // TODO optimize - let observer = observers.match_name_type::(&self.name).unwrap(); + // TODO Replace with match_name_type when stable + let observer = observers.match_name::(&self.name).unwrap(); let size = observer.usable_count(); let initial = observer.initial(); @@ -359,7 +359,8 @@ where observers: &OT, _exit_kind: &ExitKind, ) -> Result { - let observer = observers.match_name_type::(&self.name).unwrap(); + // TODO Replace with match_name_type when stable + let observer = observers.match_name::(&self.name).unwrap(); let size = observer.usable_count(); let mut hit_target: bool = false; //check if we've hit any targets. diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index c75fec1544..d9f5a2295d 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -4,6 +4,7 @@ pub mod map; pub use map::*; +use alloc::string::{String, ToString}; use serde::{Deserialize, Serialize}; use crate::{ @@ -409,6 +410,7 @@ impl Default for TimeoutFeedback { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct TimeFeedback { exec_time: Option, + name: String, } impl Feedback for TimeFeedback @@ -424,7 +426,8 @@ where where OT: ObserversTuple, { - let observer = observers.match_first_type::().unwrap(); + // TODO Replace with match_name_type when stable + let observer = observers.match_name::(self.name()).unwrap(); self.exec_time = *observer.last_runtime(); Ok(false) } @@ -448,18 +451,22 @@ where impl Named for TimeFeedback { #[inline] fn name(&self) -> &str { - "TimeFeedback" + self.name.as_str() } } impl TimeFeedback { - pub fn new() -> Self { - Self { exec_time: None } + pub fn new(name: &'static str) -> Self { + Self { + exec_time: None, + name: name.to_string(), + } } -} -impl Default for TimeFeedback { - fn default() -> Self { - Self::new() + pub fn new_with_observer(observer: &TimeObserver) -> Self { + Self { + exec_time: None, + name: observer.name().to_string(), + } } } diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index bf7037bba0..76dc689faf 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -3,6 +3,7 @@ Welcome to libAFL */ #![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "RUSTC_IS_NIGHTLY", feature(specialization))] #[macro_use] extern crate alloc; diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index 169cac1206..f97c03d157 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -4,11 +4,12 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; +use core::slice::from_raw_parts_mut; use serde::{Deserialize, Serialize}; use crate::{ bolts::{ - ownedref::{OwnedArrayPtrMut, OwnedPtr}, + ownedref::{OwnedRefMut, OwnedSliceMut}, tuples::Named, }, executors::HasExecHooks, @@ -57,24 +58,24 @@ where /// The Map Observer retrieves the state of a map, /// that will get updated by the target. /// A well-known example is the AFL-Style coverage map. -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] #[allow(clippy::unsafe_derive_deserialize)] -pub struct StdMapObserver +pub struct StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { - map: OwnedArrayPtrMut, + map: OwnedSliceMut<'a, T>, initial: T, name: String, } -impl Observer for StdMapObserver where +impl<'a, T> Observer for StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned { } -impl HasExecHooks for StdMapObserver +impl<'a, EM, I, S, T> HasExecHooks for StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, Self: MapObserver, @@ -85,7 +86,7 @@ where } } -impl Named for StdMapObserver +impl<'a, T> Named for StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { @@ -95,7 +96,7 @@ where } } -impl MapObserver for StdMapObserver +impl<'a, T> MapObserver for StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { @@ -125,16 +126,15 @@ where } } -impl StdMapObserver +impl<'a, T> StdMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { /// Creates a new MapObserver - pub fn new(name: &'static str, map: &'static mut [T], len: usize) -> Self { - assert!(map.len() >= len); + pub fn new(name: &'static str, map: &'a mut [T]) -> Self { let initial = if map.is_empty() { T::default() } else { map[0] }; Self { - map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), len)), + map: OwnedSliceMut::Ref(map), name: name.to_string(), initial, } @@ -144,7 +144,7 @@ where pub fn new_owned(name: &'static str, map: Vec) -> Self { let initial = if map.is_empty() { T::default() } else { map[0] }; Self { - map: OwnedArrayPtrMut::Owned(map), + map: OwnedSliceMut::Owned(map), name: name.to_string(), initial, } @@ -156,7 +156,7 @@ where pub unsafe fn new_from_ptr(name: &'static str, map_ptr: *mut T, len: usize) -> Self { let initial = if len > 0 { *map_ptr } else { T::default() }; StdMapObserver { - map: OwnedArrayPtrMut::ArrayPtr((map_ptr, len)), + map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, len)), name: name.to_string(), initial, } @@ -164,25 +164,25 @@ where } /// Overlooking a variable bitmap -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Debug)] #[serde(bound = "T: serde::de::DeserializeOwned")] #[allow(clippy::unsafe_derive_deserialize)] -pub struct VariableMapObserver +pub struct VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { - map: OwnedArrayPtrMut, - size: OwnedPtr, + map: OwnedSliceMut<'a, T>, + size: OwnedRefMut<'a, usize>, initial: T, name: String, } -impl Observer for VariableMapObserver where +impl<'a, T> Observer for VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned { } -impl HasExecHooks for VariableMapObserver +impl<'a, EM, I, S, T> HasExecHooks for VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { @@ -192,7 +192,7 @@ where } } -impl Named for VariableMapObserver +impl<'a, T> Named for VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { @@ -202,7 +202,7 @@ where } } -impl MapObserver for VariableMapObserver +impl<'a, T> MapObserver for VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { @@ -237,16 +237,16 @@ where } } -impl VariableMapObserver +impl<'a, T> VariableMapObserver<'a, T> where T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, { /// Creates a new MapObserver - pub fn new(name: &'static str, map: &'static mut [T], size: *const usize) -> Self { + pub fn new(name: &'static str, map: &'a mut [T], size: &'a mut usize) -> Self { let initial = if map.is_empty() { T::default() } else { map[0] }; Self { - map: OwnedArrayPtrMut::ArrayPtr((map.as_mut_ptr(), map.len())), - size: OwnedPtr::Ptr(size), + map: OwnedSliceMut::Ref(map), + size: OwnedRefMut::Ref(size), name: name.into(), initial, } @@ -254,17 +254,17 @@ where /// Creates a new MapObserver from a raw pointer /// # Safety - /// Dereferences map_ptr with up to max_len elements of size_ptr. + /// Dereferences map_ptr with up to max_len elements of size. pub unsafe fn new_from_ptr( name: &'static str, map_ptr: *mut T, max_len: usize, - size_ptr: *const usize, + size: &'a mut usize, ) -> Self { let initial = if max_len > 0 { *map_ptr } else { T::default() }; VariableMapObserver { - map: OwnedArrayPtrMut::ArrayPtr((map_ptr, max_len)), - size: OwnedPtr::Ptr(size_ptr), + map: OwnedSliceMut::Ref(from_raw_parts_mut(map_ptr, max_len)), + size: OwnedRefMut::Ref(size), name: name.into(), initial, } diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index ef81ccd012..d112262ba7 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -8,7 +8,7 @@ use core::time::Duration; use serde::{Deserialize, Serialize}; use crate::{ - bolts::tuples::{MatchFirstType, MatchNameAndType, MatchType, Named}, + bolts::tuples::{MatchName, Named}, executors::HasExecHooks, utils::current_time, Error, @@ -16,7 +16,7 @@ use crate::{ /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'static { +pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned { /// The testcase finished execution, calculate any changes. /// Reserved for future use. #[inline] @@ -26,10 +26,7 @@ pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned + 'st } /// A haskell-style tuple of observers -pub trait ObserversTuple: - MatchNameAndType + MatchType + MatchFirstType + serde::Serialize + serde::de::DeserializeOwned -{ -} +pub trait ObserversTuple: MatchName + serde::Serialize + serde::de::DeserializeOwned {} impl ObserversTuple for () {} @@ -99,7 +96,7 @@ mod tests { fn test_observer_serde() { let obv = tuple_list!( TimeObserver::new("time"), - StdMapObserver::new("map", unsafe { &mut MAP }, unsafe { MAP.len() }) + StdMapObserver::new("map", unsafe { &mut MAP }) ); let vec = postcard::to_allocvec(&obv).unwrap(); println!("{:?}", vec); diff --git a/libafl_frida/src/asan_rt.rs b/libafl_frida/src/asan_rt.rs index cb6f46c17b..17f1a44409 100644 --- a/libafl_frida/src/asan_rt.rs +++ b/libafl_frida/src/asan_rt.rs @@ -1663,7 +1663,7 @@ impl HasExecHooks for AsanErrorsObserver { impl Named for AsanErrorsObserver { #[inline] fn name(&self) -> &str { - "AsanErrorsObserver" + "AsanErrors" } } @@ -1710,7 +1710,7 @@ where _exit_kind: &ExitKind, ) -> Result { let observer = observers - .match_first_type::() + .match_name::("AsanErrors") .expect("An AsanErrorsFeedback needs an AsanErrorsObserver"); match observer.errors() { None => Ok(false), @@ -1742,7 +1742,7 @@ where impl Named for AsanErrorsFeedback { #[inline] fn name(&self) -> &str { - "AsanErrorsFeedback" + "AsanErrors" } }