diff --git a/README.md b/README.md index 0765abd1e62..d1fd0ed1b86 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su Even though we will gladly assist you in finishing up your PR, try to - keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26)) -- run `cargo fmt` on your code before pushing +- run `cargo +nightly fmt` on your code before pushing - check the output of `cargo clippy --all` or `./clippy.sh` - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. diff --git a/fuzzers/baby_fuzzer_grimoire/src/main.rs b/fuzzers/baby_fuzzer_grimoire/src/main.rs index df84a521921..0f5a7c20838 100644 --- a/fuzzers/baby_fuzzer_grimoire/src/main.rs +++ b/fuzzers/baby_fuzzer_grimoire/src/main.rs @@ -15,7 +15,7 @@ use libafl::{ GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator, GrimoireStringReplacementMutator, Tokens, }, - observers::StdMapObserver, + observers::{CanTrack, StdMapObserver}, schedulers::QueueScheduler, stages::{mutational::StdMutationalStage, GeneralizationStage}, state::StdState, @@ -83,9 +83,11 @@ pub fn main() { }; // Create an observation channel using the signals map - let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; + let observer = unsafe { + StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()).track_novelties() + }; // Feedback to rate the interestingness of an input - let mut feedback = MaxMapFeedback::tracking(&observer, false, true); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not let mut objective = CrashFeedback::new(); diff --git a/fuzzers/baby_fuzzer_swap_differential/Makefile.toml b/fuzzers/baby_fuzzer_swap_differential/Makefile.toml index 08b52d4b27d..bff07df1769 100644 --- a/fuzzers/baby_fuzzer_swap_differential/Makefile.toml +++ b/fuzzers/baby_fuzzer_swap_differential/Makefile.toml @@ -19,6 +19,9 @@ command = "cargo" args = ["build" , "--profile", "${PROFILE}", "--bin", "${FUZZER_NAME}"] dependencies = [ "cc" ] +[tasks.build] +alias = "fuzzer" + # Run the fuzzer [tasks.run] command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}" @@ -50,4 +53,4 @@ clear = true script_runner="@shell" script=''' cargo clean -''' \ No newline at end of file +''' diff --git a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs index 6a65550ca1a..a71912c38e2 100644 --- a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs @@ -54,7 +54,7 @@ pub fn main() { // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let mut feedback = MaxMapFeedback::new(&edges_observer); // A feedback to choose if an input is a solution or not // We want to do the same crash deduplication that AFL does diff --git a/fuzzers/forkserver_libafl_cc/src/main.rs b/fuzzers/forkserver_libafl_cc/src/main.rs index 05ceb796165..79a6cb1e17b 100644 --- a/fuzzers/forkserver_libafl_cc/src/main.rs +++ b/fuzzers/forkserver_libafl_cc/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ inputs::BytesInput, monitors::SimpleMonitor, mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -101,8 +101,9 @@ pub fn main() { let shmem_buf = shmem.as_mut_slice(); // Create an observation channel using the signals map - let edges_observer = - unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; + let edges_observer = unsafe { + HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices() + }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -111,7 +112,7 @@ pub fn main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -151,7 +152,7 @@ pub fn main() { let mut mgr = SimpleEventManager::new(monitor); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/forkserver_simple/src/main.rs b/fuzzers/forkserver_simple/src/main.rs index 558bbce11d8..2d59bbe4a3f 100644 --- a/fuzzers/forkserver_simple/src/main.rs +++ b/fuzzers/forkserver_simple/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ inputs::BytesInput, monitors::SimpleMonitor, mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -101,8 +101,9 @@ pub fn main() { let shmem_buf = shmem.as_mut_slice(); // Create an observation channel using the signals map - let edges_observer = - unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; + let edges_observer = unsafe { + HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices() + }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -111,7 +112,7 @@ pub fn main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -151,7 +152,7 @@ pub fn main() { let mut mgr = SimpleEventManager::new(monitor); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/frida_executable_libpng/src/fuzzer.rs b/fuzzers/frida_executable_libpng/src/fuzzer.rs index 7d6240d3e0f..56130cd8df3 100644 --- a/fuzzers/frida_executable_libpng/src/fuzzer.rs +++ b/fuzzers/frida_executable_libpng/src/fuzzer.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use std::{path::PathBuf, ptr::null}; use frida_gum::Gum; @@ -20,7 +16,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -39,7 +35,7 @@ use libafl_bolts::{ #[cfg(unix)] use libafl_frida::asan::{ asan_rt::AsanRuntime, - errors::{AsanErrorsFeedback, AsanErrorsObserver}, + errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS}, }; use libafl_frida::{ cmplog_rt::CmpLogRuntime, @@ -48,6 +44,10 @@ use libafl_frida::{ helper::FridaInstrumentationHelper, }; use libafl_targets::cmplog::CmpLogObserver; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32) { color_backtrace::install(); @@ -104,7 +104,7 @@ unsafe fn fuzz( let coverage = CoverageRuntime::new(); #[cfg(unix)] - let asan = AsanRuntime::new(options); + let asan = AsanRuntime::new(&options); #[cfg(unix)] let mut frida_helper = @@ -118,7 +118,8 @@ unsafe fn fuzz( "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -127,7 +128,7 @@ unsafe fn fuzz( // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -177,7 +178,8 @@ unsafe fn fuzz( let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -233,7 +235,8 @@ unsafe fn fuzz( "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -242,7 +245,7 @@ unsafe fn fuzz( // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -290,7 +293,8 @@ unsafe fn fuzz( let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -361,7 +365,8 @@ unsafe fn fuzz( "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -370,7 +375,7 @@ unsafe fn fuzz( // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -418,7 +423,8 @@ unsafe fn fuzz( let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/frida_gdiplus/src/fuzzer.rs b/fuzzers/frida_gdiplus/src/fuzzer.rs index 54a0e80fca7..4ec52e38872 100644 --- a/fuzzers/frida_gdiplus/src/fuzzer.rs +++ b/fuzzers/frida_gdiplus/src/fuzzer.rs @@ -26,7 +26,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -113,7 +113,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -122,7 +123,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -171,7 +172,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -227,7 +229,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -236,7 +239,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -284,7 +287,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -356,7 +360,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -365,7 +370,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -413,7 +418,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index ca3f223cd45..83687093d33 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use std::path::PathBuf; use frida_gum::Gum; @@ -20,7 +16,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -39,7 +35,7 @@ use libafl_bolts::{ #[cfg(unix)] use libafl_frida::asan::{ asan_rt::AsanRuntime, - errors::{AsanErrorsFeedback, AsanErrorsObserver}, + errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS}, }; use libafl_frida::{ cmplog_rt::CmpLogRuntime, @@ -48,6 +44,10 @@ use libafl_frida::{ helper::FridaInstrumentationHelper, }; use libafl_targets::cmplog::CmpLogObserver; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// The main fn, usually parsing parameters, and starting the fuzzer pub fn main() { @@ -108,7 +108,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -117,7 +118,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -167,7 +168,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -224,7 +226,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -233,7 +236,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -281,7 +284,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -352,7 +356,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { "edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE, - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -361,7 +366,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -409,7 +414,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> { let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench/src/lib.rs b/fuzzers/fuzzbench/src/lib.rs index 61ddc4a7516..0946984bbeb 100644 --- a/fuzzers/fuzzbench/src/lib.rs +++ b/fuzzers/fuzzbench/src/lib.rs @@ -28,7 +28,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -242,14 +242,15 @@ fn fuzz( // 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 = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); let cmplog_observer = CmpLogObserver::new("cmplog", true); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -307,11 +308,10 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_ctx/src/lib.rs b/fuzzers/fuzzbench_ctx/src/lib.rs index 09df7caca6e..a2ec8919e96 100644 --- a/fuzzers/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/fuzzbench_ctx/src/lib.rs @@ -31,7 +31,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -252,14 +252,15 @@ fn fuzz( "edges", OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE), ) - }); + }) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); let cmplog_observer = CmpLogObserver::new("cmplog", true); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -317,11 +318,10 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs index 427a0d9a43d..f15a244fee8 100644 --- a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs @@ -26,7 +26,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{ConstMapObserver, HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, @@ -242,6 +242,7 @@ fn fuzz( "edges", edges.as_mut_ptr(), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -250,7 +251,7 @@ fn fuzz( // Create an observation channel using cmplog map let cmplog_observer = unsafe { CmpLogObserver::with_map_ptr("cmplog", cmplog_map_ptr, true) }; - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -299,11 +300,10 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - PowerSchedule::FAST, - )); + PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_forkserver/src/main.rs b/fuzzers/fuzzbench_forkserver/src/main.rs index 6c267c74862..63929e01f05 100644 --- a/fuzzers/fuzzbench_forkserver/src/main.rs +++ b/fuzzers/fuzzbench_forkserver/src/main.rs @@ -21,7 +21,9 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver}, + observers::{ + CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver, + }, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -248,13 +250,14 @@ fn fuzz( std::env::set_var("AFL_MAP_SIZE", format!("{}", MAP_SIZE)); // Create an observation channel using the hitcounts map of AFL++ - let edges_observer = - unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; + let edges_observer = unsafe { + HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices() + }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -300,11 +303,14 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::EXPLORE), - )); + StdWeightedScheduler::with_schedule( + &mut state, + &edges_observer, + Some(PowerSchedule::EXPLORE), + ), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_forkserver_cmplog/src/main.rs b/fuzzers/fuzzbench_forkserver_cmplog/src/main.rs index 15ed5d05fb2..7a16862119a 100644 --- a/fuzzers/fuzzbench_forkserver_cmplog/src/main.rs +++ b/fuzzers/fuzzbench_forkserver_cmplog/src/main.rs @@ -21,7 +21,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, StdMOptMutator, Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -251,13 +251,14 @@ fn fuzz( std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}")); // Create an observation channel using the hitcounts map of AFL++ - let edges_observer = - unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; + let edges_observer = unsafe { + HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices() + }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -303,11 +304,14 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::EXPLORE), - )); + StdWeightedScheduler::with_schedule( + &mut state, + &edges_observer, + Some(PowerSchedule::EXPLORE), + ), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index b2be0c5b014..bbc4cd16a03 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -25,7 +25,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, @@ -53,6 +53,7 @@ use libafl_qemu::{ elf::EasyElf, filter_qemu_args, hooks::QemuHooks, + Emulator, GuestReg, //snapshot::QemuSnapshotHelper, MmapPerms, @@ -259,6 +260,7 @@ fn fuzz( edges_map_mut_slice(), addr_of_mut!(MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -267,7 +269,7 @@ fn fuzz( // Create an observation channel using cmplog map let cmplog_observer = CmpLogObserver::new("cmplog", true); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -316,11 +318,10 @@ fn fuzz( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - PowerSchedule::FAST, - )); + PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/fuzzbench_text/src/lib.rs b/fuzzers/fuzzbench_text/src/lib.rs index 1967d53b468..ead29064603 100644 --- a/fuzzers/fuzzbench_text/src/lib.rs +++ b/fuzzers/fuzzbench_text/src/lib.rs @@ -34,7 +34,7 @@ use libafl::{ token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -310,14 +310,15 @@ fn fuzz_binary( // 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 = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); let cmplog_observer = CmpLogObserver::new("cmplog", true); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -374,11 +375,14 @@ fn fuzz_binary( let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::EXPLORE), - )); + StdWeightedScheduler::with_schedule( + &mut state, + &edges_observer, + Some(PowerSchedule::EXPLORE), + ), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -516,7 +520,9 @@ fn fuzz_text( // 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 = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }) + .track_indices() + .track_novelties(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -524,7 +530,7 @@ fn fuzz_text( let cmplog_observer = CmpLogObserver::new("cmplog", true); // New maximization map feedback linked to the edges observer and the feedback state - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -594,11 +600,14 @@ fn fuzz_text( let grimoire = StdMutationalStage::transforming(grimoire_mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::EXPLORE), - )); + StdWeightedScheduler::with_schedule( + &mut state, + &edges_observer, + Some(PowerSchedule::EXPLORE), + ), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libafl_atheris/src/lib.rs b/fuzzers/libafl_atheris/src/lib.rs index c148040ddd9..95f2e92694a 100644 --- a/fuzzers/libafl_atheris/src/lib.rs +++ b/fuzzers/libafl_atheris/src/lib.rs @@ -25,7 +25,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{StdMutationalStage, TracingStage}, state::{HasCorpus, StdState}, @@ -136,7 +136,8 @@ pub extern "C" fn LLVMFuzzerRunDriver( let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_slice( "edges", edges.into_iter().next().unwrap(), - )); + )) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -148,7 +149,7 @@ pub extern "C" fn LLVMFuzzerRunDriver( // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -183,7 +184,8 @@ pub extern "C" fn LLVMFuzzerRunDriver( } // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index 8bb56ac48b6..5fe52363d40 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; #[cfg(feature = "crash")] use std::ptr; @@ -22,7 +18,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -37,6 +33,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// The main fn, `no_mangle` as it is a C main #[cfg(not(test))] @@ -85,12 +85,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM, )) + .track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -147,11 +148,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_accounting/src/lib.rs b/fuzzers/libfuzzer_libpng_accounting/src/lib.rs index 274c8e8ec52..750dd7b2de8 100644 --- a/fuzzers/libfuzzer_libpng_accounting/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_accounting/src/lib.rs @@ -2,10 +2,6 @@ //! The example harness is built for libpng. //! In this example, you will see the use of the `launcher` feature. //! The `launcher` will spawn new processes for each cpu core. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; use std::{env, net::SocketAddr, path::PathBuf}; @@ -23,7 +19,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{CoverageAccountingScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -40,6 +36,10 @@ use libafl_bolts::{ use libafl_targets::{ libfuzzer_initialize, libfuzzer_test_one_input, ACCOUNTING_MEMOP_MAP, EDGES_MAP, MAX_EDGES_NUM, }; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// Parse a millis string to a [`Duration`]. Used for arg parsing. fn timeout_from_millis_str(time: &str) -> Result { @@ -55,11 +55,11 @@ fn timeout_from_millis_str(time: &str) -> Result { )] struct Opt { #[arg( - short, - long, - value_parser = Cores::from_cmdline, - help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", - name = "CORES" + short, + long, + value_parser = Cores::from_cmdline, + help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", + name = "CORES" )] cores: Cores, @@ -94,12 +94,12 @@ struct Opt { output: PathBuf, #[arg( - value_parser = timeout_from_millis_str, - short, - long, - help = "Set the execution timeout in milliseconds, default is 10000", - name = "TIMEOUT", - default_value = "10000" + value_parser = timeout_from_millis_str, + short, + long, + help = "Set the execution timeout in milliseconds, default is 10000", + name = "TIMEOUT", + default_value = "10000" )] timeout: Duration, /* @@ -140,7 +140,8 @@ pub extern "C" fn libafl_main() { // Create an observation channel using the coverage map let edges_observer = HitcountsMapObserver::new(unsafe { StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM) - }); + }) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -149,7 +150,7 @@ pub extern "C" fn libafl_main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -194,10 +195,12 @@ pub extern "C" fn libafl_main() { let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // A minimization+queue policy to get testcasess from the corpus - let scheduler = - CoverageAccountingScheduler::new(&mut state, QueueScheduler::new(), unsafe { - &ACCOUNTING_MEMOP_MAP - }); + let scheduler = CoverageAccountingScheduler::new( + &edges_observer, + &mut state, + QueueScheduler::new(), + unsafe { &ACCOUNTING_MEMOP_MAP }, + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs b/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs index 75df7976949..4a8867f8418 100644 --- a/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_aflpp_ui/src/lib.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; #[cfg(feature = "crash")] use std::ptr; @@ -22,7 +18,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -37,6 +33,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// The main fn, `no_mangle` as it is a C main #[cfg(not(test))] @@ -99,12 +99,13 @@ fn fuzz( EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM, )) + .track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -163,11 +164,10 @@ fn fuzz( let mut stages = tuple_list!(calibration, power, aflstats); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_centralized/src/lib.rs b/fuzzers/libfuzzer_libpng_centralized/src/lib.rs index e9ee97837b2..ee3bafcff2b 100644 --- a/fuzzers/libfuzzer_libpng_centralized/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_centralized/src/lib.rs @@ -2,10 +2,6 @@ //! The example harness is built for libpng. //! In this example, you will see the use of the `launcher` feature. //! The `launcher` will spawn new processes for each cpu core. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; use std::{env, net::SocketAddr, path::PathBuf}; @@ -23,7 +19,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -38,6 +34,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// Parse a millis string to a [`Duration`]. Used for arg parsing. fn timeout_from_millis_str(time: &str) -> Result { @@ -53,11 +53,11 @@ fn timeout_from_millis_str(time: &str) -> Result { )] struct Opt { #[arg( - short, - long, - value_parser = Cores::from_cmdline, - help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", - name = "CORES" + short, + long, + value_parser = Cores::from_cmdline, + help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", + name = "CORES" )] cores: Cores, @@ -92,12 +92,12 @@ struct Opt { output: PathBuf, #[arg( - value_parser = timeout_from_millis_str, - short, - long, - help = "Set the exeucution timeout in milliseconds, default is 10000", - name = "TIMEOUT", - default_value = "10000" + value_parser = timeout_from_millis_str, + short, + long, + help = "Set the exeucution timeout in milliseconds, default is 10000", + name = "TIMEOUT", + default_value = "10000" )] timeout: Duration, /* @@ -138,7 +138,8 @@ pub extern "C" fn libafl_main() { let mut run_client = |state: Option<_>, mut mgr, _core_id: CoreId| { // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -147,7 +148,7 @@ pub extern "C" fn libafl_main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -192,7 +193,8 @@ pub extern "C" fn libafl_main() { let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_cmin/src/lib.rs b/fuzzers/libfuzzer_libpng_cmin/src/lib.rs index 2b2fb5d7ef3..44b33568350 100644 --- a/fuzzers/libfuzzer_libpng_cmin/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_cmin/src/lib.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; #[cfg(feature = "crash")] use std::ptr; @@ -25,7 +21,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -40,6 +36,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// The main fn, `no_mangle` as it is a C main #[cfg(not(test))] @@ -82,14 +82,15 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re }; // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); let minimizer = StdCorpusMinimizer::new(&edges_observer); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -146,11 +147,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs index 5d6392a4d36..d8d50091513 100644 --- a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs @@ -2,10 +2,6 @@ //! The example harness is built for libpng. //! In this example, you will see the use of the `launcher` feature. //! The `launcher` will spawn new processes for each cpu core. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; use std::{env, net::SocketAddr, path::PathBuf}; @@ -23,7 +19,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -38,6 +34,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// Parse a millis string to a [`Duration`]. Used for arg parsing. fn timeout_from_millis_str(time: &str) -> Result { @@ -53,11 +53,11 @@ fn timeout_from_millis_str(time: &str) -> Result { )] struct Opt { #[arg( - short, - long, - value_parser = Cores::from_cmdline, - help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", - name = "CORES" + short, + long, + value_parser = Cores::from_cmdline, + help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", + name = "CORES" )] cores: Cores, @@ -92,12 +92,12 @@ struct Opt { output: PathBuf, #[arg( - value_parser = timeout_from_millis_str, - short, - long, - help = "Set the exeucution timeout in milliseconds, default is 10000", - name = "TIMEOUT", - default_value = "10000" + value_parser = timeout_from_millis_str, + short, + long, + help = "Set the exeucution timeout in milliseconds, default is 10000", + name = "TIMEOUT", + default_value = "10000" )] timeout: Duration, /* @@ -139,7 +139,8 @@ pub extern "C" fn libafl_main() { let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| { // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -148,7 +149,7 @@ pub extern "C" fn libafl_main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -193,7 +194,8 @@ pub extern "C" fn libafl_main() { let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs index a3729914f80..2b041f514bd 100644 --- a/fuzzers/libfuzzer_libpng_norestart/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_norestart/src/lib.rs @@ -2,9 +2,6 @@ //! The example harness is built for libpng. //! In this example, you will see the use of the `launcher` feature. //! The `launcher` will spawn new processes for each cpu core. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; use core::time::Duration; use std::{env, net::SocketAddr, path::PathBuf}; @@ -26,7 +23,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::mutational::StdMutationalStage, state::{HasCorpus, StdState}, @@ -41,6 +38,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// Parse a millis string to a [`Duration`]. Used for arg parsing. fn timeout_from_millis_str(time: &str) -> Result { @@ -56,11 +57,11 @@ fn timeout_from_millis_str(time: &str) -> Result { )] struct Opt { #[arg( - short, - long, - value_parser = Cores::from_cmdline, - help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", - name = "CORES" + short, + long, + value_parser = Cores::from_cmdline, + help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.", + name = "CORES" )] cores: Cores, @@ -95,12 +96,12 @@ struct Opt { output: PathBuf, #[arg( - value_parser = timeout_from_millis_str, - short, - long, - help = "Set the exeucution timeout in milliseconds, default is 10000", - name = "TIMEOUT", - default_value = "10000" + value_parser = timeout_from_millis_str, + short, + long, + help = "Set the exeucution timeout in milliseconds, default is 10000", + name = "TIMEOUT", + default_value = "10000" )] timeout: Duration, @@ -163,7 +164,8 @@ pub extern "C" fn libafl_main() { mut restarting_mgr: LlmpRestartingEventManager<_, _, _>, core_id| { // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -172,7 +174,7 @@ pub extern "C" fn libafl_main() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -217,7 +219,8 @@ pub extern "C" fn libafl_main() { let mut stages = tuple_list!(StdMutationalStage::new(mutator)); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_libpng_tcp_manager/src/lib.rs b/fuzzers/libfuzzer_libpng_tcp_manager/src/lib.rs index 17eebbbd63b..e1a49198be0 100644 --- a/fuzzers/libfuzzer_libpng_tcp_manager/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_tcp_manager/src/lib.rs @@ -1,9 +1,5 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for libpng. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use core::time::Duration; #[cfg(feature = "crash")] use std::ptr; @@ -22,7 +18,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -37,6 +33,10 @@ use libafl_bolts::{ AsSlice, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; /// The main fn, `no_mangle` as it is a C main #[no_mangle] @@ -83,12 +83,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM, )) + .track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -145,11 +146,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index 913eeaf7ad6..12866edb9e1 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -19,7 +19,7 @@ use libafl::{ scheduled::{havoc_mutations, StdScheduledMutator}, token_mutations::I2SRandReplace, }, - observers::TimeObserver, + observers::{CanTrack, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -68,7 +68,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // 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 = unsafe { std_edges_map_observer("edges") }; + let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -79,7 +79,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -109,7 +109,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re println!("We're a client, let's fuzz :)"); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs index 840278baf61..5b712c4c42f 100644 --- a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs +++ b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs @@ -1,11 +1,7 @@ //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! The example harness is built for `stb_image`. -use mimalloc::MiMalloc; -#[global_allocator] -static GLOBAL: MiMalloc = MiMalloc; - use std::{ - env, + env, fs, path::PathBuf, process::{Child, Command, Stdio}, time::Duration, @@ -32,7 +28,7 @@ use libafl::{ serialization_format::{DEFAULT_ENV_NAME, DEFAULT_SIZE}, ConcolicObserver, }, - TimeObserver, + TimeObserver, CanTrack, }, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ @@ -52,6 +48,10 @@ use libafl_bolts::{ use libafl_targets::{ libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver, }; +use mimalloc::MiMalloc; + +#[global_allocator] +static GLOBAL: MiMalloc = MiMalloc; #[derive(Debug, Parser)] struct Opt { @@ -60,7 +60,6 @@ struct Opt { concolic: bool, } -use std::fs; pub fn main() { // Registry the metadata types used in this fuzzer // Needed only on no_std @@ -107,7 +106,7 @@ fn fuzz( // 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 = unsafe { std_edges_map_observer("edges") }; + let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -118,7 +117,7 @@ fn fuzz( // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -148,7 +147,7 @@ fn fuzz( println!("We're a client, let's fuzz :)"); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/libfuzzer_windows_asan/src/lib.rs b/fuzzers/libfuzzer_windows_asan/src/lib.rs index 2f0eeab1daa..9e84f19971d 100644 --- a/fuzzers/libfuzzer_windows_asan/src/lib.rs +++ b/fuzzers/libfuzzer_windows_asan/src/lib.rs @@ -11,7 +11,7 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, }, @@ -61,12 +61,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re }; // Create an observation channel using the coverage map - let edges_observer = unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")) }; + let edges_observer = + unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")).track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -112,11 +113,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - Some(PowerSchedule::FAST), - )); + StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/qemu_cmin/src/fuzzer.rs b/fuzzers/qemu_cmin/src/fuzzer.rs index 8787b053a73..f92cfbd651e 100644 --- a/fuzzers/qemu_cmin/src/fuzzer.rs +++ b/fuzzers/qemu_cmin/src/fuzzer.rs @@ -30,6 +30,7 @@ use libafl_bolts::{ use libafl_qemu::{ edges::{QemuEdgeCoverageChildHelper, EDGES_MAP_PTR, EDGES_MAP_SIZE}, elf::EasyElf, + emu::Emulator, ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitReason, QemuExitReasonError, QemuForkExecutor, QemuHooks, QemuShutdownCause, Regs, }; @@ -63,10 +64,10 @@ impl From for Str { #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] #[command( - name = format!("qemu_cmin-{}",env!("CPU_TARGET")), - version = Version::default(), - about, - long_about = "Tool for generating minimizing corpus using QEMU instrumentation" +name = format ! ("qemu_cmin-{}", env ! ("CPU_TARGET")), +version = Version::default(), +about, +long_about = "Tool for generating minimizing corpus using QEMU instrumentation" )] pub struct FuzzerOptions { #[arg(long, help = "Output directory")] @@ -171,7 +172,7 @@ pub fn fuzz() -> Result<(), Error> { )) }; - let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let mut feedback = MaxMapFeedback::new(&edges_observer); #[allow(clippy::let_unit_value)] let mut objective = (); diff --git a/fuzzers/qemu_launcher/src/instance.rs b/fuzzers/qemu_launcher/src/instance.rs index 27c29e900e2..935522f459e 100644 --- a/fuzzers/qemu_launcher/src/instance.rs +++ b/fuzzers/qemu_launcher/src/instance.rs @@ -18,7 +18,7 @@ use libafl::{ scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, }, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, @@ -81,12 +81,13 @@ impl<'a, M: Monitor> Instance<'a, M> { edges_map_mut_slice(), addr_of_mut!(MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -124,11 +125,10 @@ impl<'a, M: Monitor> Instance<'a, M> { }; // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( - &mut state, + let scheduler = IndexesLenTimeMinimizerScheduler::new( &edges_observer, - PowerSchedule::FAST, - )); + PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST), + ); let observers = tuple_list!(edges_observer, time_observer); diff --git a/fuzzers/qemu_systemmode/src/fuzzer_breakpoint.rs b/fuzzers/qemu_systemmode/src/fuzzer_breakpoint.rs index 9dceeb89b7b..4ad5ead1a39 100644 --- a/fuzzers/qemu_systemmode/src/fuzzer_breakpoint.rs +++ b/fuzzers/qemu_systemmode/src/fuzzer_breakpoint.rs @@ -13,7 +13,7 @@ use libafl::{ inputs::BytesInput, monitors::MultiMonitor, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{CalibrationStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -157,6 +157,7 @@ pub fn fuzz() { edges_map_mut_slice(), addr_of_mut!(MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -166,7 +167,7 @@ pub fn fuzz() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, true), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -194,7 +195,8 @@ pub fn fuzz() { }); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -206,7 +208,7 @@ pub fn fuzz() { // Setup an havoc mutator with a mutational stage let mutator = StdScheduledMutator::new(havoc_mutations()); - let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); + let calibration_feedback = MaxMapFeedback::new(&edges_observer); let mut stages = tuple_list!( StdMutationalStage::new(mutator), CalibrationStage::new(&calibration_feedback) diff --git a/fuzzers/qemu_systemmode/src/fuzzer_classic.rs b/fuzzers/qemu_systemmode/src/fuzzer_classic.rs index d0e2c9d5101..3ca47e27844 100644 --- a/fuzzers/qemu_systemmode/src/fuzzer_classic.rs +++ b/fuzzers/qemu_systemmode/src/fuzzer_classic.rs @@ -13,7 +13,7 @@ use libafl::{ inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::StdMutationalStage, state::{HasCorpus, StdState}, @@ -164,6 +164,7 @@ pub fn fuzz() { edges_map_mut_slice(), addr_of_mut!(MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -173,7 +174,7 @@ pub fn fuzz() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, true), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -201,7 +202,8 @@ pub fn fuzz() { }); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/qemu_systemmode/src/fuzzer_sync_exit.rs b/fuzzers/qemu_systemmode/src/fuzzer_sync_exit.rs index 53e77e06fa6..2eaec741039 100644 --- a/fuzzers/qemu_systemmode/src/fuzzer_sync_exit.rs +++ b/fuzzers/qemu_systemmode/src/fuzzer_sync_exit.rs @@ -13,7 +13,7 @@ use libafl::{ inputs::BytesInput, monitors::MultiMonitor, mutators::scheduled::{havoc_mutations, StdScheduledMutator}, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{CalibrationStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -98,6 +98,7 @@ pub fn fuzz() { edges_map_mut_slice(), addr_of_mut!(MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -107,7 +108,7 @@ pub fn fuzz() { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, true), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -135,7 +136,8 @@ pub fn fuzz() { }); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -147,7 +149,7 @@ pub fn fuzz() { // Setup an havoc mutator with a mutational stage let mutator = StdScheduledMutator::new(havoc_mutations()); - let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); + let calibration_feedback = MaxMapFeedback::new(&edges_observer); let mut stages = tuple_list!( StdMutationalStage::new(mutator), CalibrationStage::new(&calibration_feedback) diff --git a/fuzzers/tutorial/src/lib.rs b/fuzzers/tutorial/src/lib.rs index 1c7fe08fe7c..1333bb9159c 100644 --- a/fuzzers/tutorial/src/lib.rs +++ b/fuzzers/tutorial/src/lib.rs @@ -15,7 +15,7 @@ use libafl::{ fuzzer::StdFuzzer, inputs::HasTargetBytes, monitors::MultiMonitor, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{powersched::PowerSchedule, PowerQueueScheduler}, stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage}, state::{HasCorpus, StdState}, @@ -81,12 +81,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re }; // Create an observation channel using the coverage map - let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + let edges_observer = + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); let calibration = CalibrationStage::new(&map_feedback); @@ -132,11 +133,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mut stages = tuple_list!(calibration, power); // A minimization+queue policy to get testcasess from the corpus - let scheduler = PacketLenMinimizerScheduler::new(PowerQueueScheduler::new( - &mut state, + let scheduler = PacketLenMinimizerScheduler::new( &edges_observer, - PowerSchedule::FAST, - )); + PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST), + ); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/fuzzers/tutorial/src/metadata.rs b/fuzzers/tutorial/src/metadata.rs index 2d17ab7d53b..192241fb346 100644 --- a/fuzzers/tutorial/src/metadata.rs +++ b/fuzzers/tutorial/src/metadata.rs @@ -32,8 +32,8 @@ where } } -pub type PacketLenMinimizerScheduler = - MinimizerScheduler; +pub type PacketLenMinimizerScheduler = + MinimizerScheduler; #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct PacketLenFeedback { diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 02baecb3d12..2cb5047b9e5 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -45,7 +45,7 @@ errors_backtrace = ["libafl_bolts/errors_backtrace"] corpus_btreemap = [] ## Enables gzip compression in certain parts of the lib -gzip = ["libafl_bolts/gzip"] +gzip = ["libafl_bolts/gzip"] ## If set, will use the `fork()` syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on `Windows`). fork = ["libafl_bolts/derive"] @@ -133,7 +133,7 @@ agpl = ["nautilus"] nautilus = ["grammartec", "std", "serde_json/std"] [build-dependencies] -reqwest = { version = "0.11", features = ["blocking"], optional = true} +reqwest = { version = "0.11", features = ["blocking"], optional = true } rustversion = "1.0" zip = { version = "0.6", optional = true } @@ -148,15 +148,15 @@ libafl_derive = { version = "0.11.2", path = "../libafl_derive", optional = true rustversion = "1.0" tuple_list = { version = "0.1.3" } -hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false } # A faster hashmap, nostd compatible +hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features = false } # A faster hashmap, nostd compatible num-traits = { version = "0.2", default-features = false } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib postcard = { version = "1.0", features = ["alloc"], default-features = false } # no_std compatible serde serialization format -bincode = {version = "1.3", optional = true } +bincode = { version = "1.3", optional = true } c2rust-bitfields = { version = "0.18", features = ["no_std"] } -ahash = { version = "0.8", default-features=false } # The hash function already used in hashbrown +ahash = { version = "0.8", default-features = false } # The hash function already used in hashbrown meminterval = { version = "0.4", features = ["serde"] } -backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver +backtrace = { version = "0.3", optional = true } # Used to get the stacktrace in StacktraceObserver typed-builder = { version = "0.16", optional = true } # Implement the builder pattern at compiletime serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } @@ -167,7 +167,7 @@ libm = "0.2.2" ratatui = { version = "0.23.0", default-features = false, features = ['crossterm'], optional = true } # Commandline rendering, for TUI Monitor crossterm = { version = "0.27.0", optional = true } -prometheus-client = { version= "0.21", optional = true} # For the prometheus monitor +prometheus-client = { version = "0.21", optional = true } # For the prometheus monitor tide = { version = "0.16.0", optional = true } async-std = { version = "1.12.0", features = ["attributes"], optional = true } futures = { version = "0.3.24", optional = true } @@ -186,6 +186,9 @@ bitvec = { version = "1.0", optional = true, features = ["serde"] } # used for s arrayvec = { version = "0.7.4", optional = true, default-features = false } # used for fixed-len collects +const_format = "0.2.32" # used for providing helpful compiler output +const_panic = "0.2.8" # similarly, for formatting const panic output + # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] } diff --git a/libafl/src/corpus/minimizer.rs b/libafl/src/corpus/minimizer.rs index e5991830cba..456a3acf61c 100644 --- a/libafl/src/corpus/minimizer.rs +++ b/libafl/src/corpus/minimizer.rs @@ -49,32 +49,25 @@ where /// /// Algorithm based on WMOPT: #[derive(Debug)] -pub struct MapCorpusMinimizer -where - E: UsesState, - E::State: HasCorpus + HasMetadata, - TS: TestcaseScore, -{ +pub struct MapCorpusMinimizer { obs_name: String, - phantom: PhantomData<(E, O, T, TS)>, + phantom: PhantomData<(C, E, O, T, TS)>, } /// Standard corpus minimizer, which weights inputs by length and time. -pub type StdCorpusMinimizer = - MapCorpusMinimizer::State>>; +pub type StdCorpusMinimizer = + MapCorpusMinimizer::State>>; -impl MapCorpusMinimizer +impl MapCorpusMinimizer where E: UsesState, E::State: HasCorpus + HasMetadata, TS: TestcaseScore, + C: Named, { /// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used /// in the future to get observed maps from an executed input. - pub fn new(obs: &O) -> Self - where - O: Named, - { + pub fn new(obs: &C) -> Self { Self { obs_name: obs.name().to_string(), phantom: PhantomData, @@ -82,10 +75,11 @@ where } } -impl CorpusMinimizer for MapCorpusMinimizer +impl CorpusMinimizer for MapCorpusMinimizer where E: UsesState, for<'a> O: MapObserver + AsIter<'a, Item = T>, + C: AsRef, E::State: HasMetadata + HasCorpus + HasExecutions, T: Copy + Hash + Eq, TS: TestcaseScore, @@ -165,10 +159,11 @@ where )?; let seed_expr = Bool::fresh_const(&ctx, "seed"); - let obs: &O = executor + let obs = executor .observers() - .match_name::(&self.obs_name) - .expect("Observer must be present."); + .match_name::(&self.obs_name) + .expect("Observer must be present.") + .as_ref(); // Store coverage, mapping coverage map indices to hit counts (if present) and the // associated seeds for the map indices with those hit counts. diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index b747716097a..c9daf2c96b2 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -1499,7 +1499,7 @@ where } /// A manager-like llmp client that converts between input types -pub struct LlmpEventConverter +pub struct LlmpEventConverter where S: UsesInput, SP: ShMemProvider + 'static, @@ -1517,7 +1517,7 @@ where phantom: PhantomData, } -impl core::fmt::Debug for LlmpEventConverter +impl core::fmt::Debug for LlmpEventConverter where SP: ShMemProvider + 'static, S: UsesInput, @@ -1539,7 +1539,7 @@ where } } -impl LlmpEventConverter +impl LlmpEventConverter where S: UsesInput + HasExecutions + HasMetadata, SP: ShMemProvider + 'static, @@ -1734,7 +1734,7 @@ where } } -impl UsesState for LlmpEventConverter +impl UsesState for LlmpEventConverter where S: State, SP: ShMemProvider, @@ -1745,7 +1745,7 @@ where type State = S; } -impl EventFirer for LlmpEventConverter +impl EventFirer for LlmpEventConverter where S: State, SP: ShMemProvider, diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 18588a93ec6..db66b8255c3 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -636,13 +636,14 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> { /// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size. #[allow(clippy::pedantic)] - pub fn build_dynamic_map( + pub fn build_dynamic_map( &mut self, - mut map_observer: MO, + mut map_observer: A, other_observers: OT, - ) -> Result, Error> + ) -> Result, Error> where - MO: Observer + MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map + MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map + A: Observer + AsRef + AsMut, OT: ObserversTuple + Prepend, S: UsesInput, S::Input: Input + HasTargetBytes, @@ -660,10 +661,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> { ); if let Some(dynamic_map_size) = self.map_size { - map_observer.truncate(dynamic_map_size); + map_observer.as_mut().truncate(dynamic_map_size); } - let observers: (MO, OT) = other_observers.prepend(map_observer); + let observers = (map_observer, other_observers); if self.uses_shmem_testcase && map.is_none() { return Err(Error::illegal_state( diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 322fecdfa59..3520dc164f8 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -23,28 +23,29 @@ use crate::{ feedbacks::{Feedback, HasObserverName}, inputs::UsesInput, monitors::{AggregatorOps, UserStats, UserStatsValue}, - observers::{MapObserver, Observer, ObserversTuple, UsesObserver}, + observers::{CanTrack, MapObserver, Observer, ObserversTuple, UsesObserver}, state::State, Error, HasMetadata, HasNamedMetadata, }; -/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``. -pub type AflMapFeedback = MapFeedback; +/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`]. +pub type AflMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents. -pub type MaxMapFeedback = MapFeedback; +pub type MaxMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to minimize the map contents. -pub type MinMapFeedback = MapFeedback; +pub type MinMapFeedback = MapFeedback; /// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions. -pub type AlwaysInterestingMapFeedback = MapFeedback; +pub type AlwaysInterestingMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is larger than `pow2` of the previous. -pub type MaxMapPow2Feedback = MapFeedback; +pub type MaxMapPow2Feedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is larger than `pow2` of the previous. -pub type MaxMapOneOrFilledFeedback = MapFeedback; +pub type MaxMapOneOrFilledFeedback = + MapFeedback; /// A `Reducer` function is used to aggregate values for the novelty search pub trait Reducer: 'static @@ -174,6 +175,7 @@ fn saturating_next_power_of_two(n: T) -> T { /// Consider as novelty if the reduced value is different from the old value. #[derive(Clone, Debug)] pub struct DifferentIsNovel {} + impl IsNovel for DifferentIsNovel where T: PartialEq + Default + Copy + 'static, @@ -187,6 +189,7 @@ where /// Only consider as novel the values which are at least the next pow2 class of the old value #[derive(Clone, Debug)] pub struct NextPow2IsNovel {} + impl IsNovel for NextPow2IsNovel where T: PrimInt + Default + Copy + 'static, @@ -207,6 +210,7 @@ where /// Only consider `T::one()` or `T::max_value()`, if they are bigger than the old value, as novel #[derive(Clone, Debug)] pub struct OneOrFilledIsNovel {} + impl IsNovel for OneOrFilledIsNovel where T: PrimInt + Default + Copy + 'static, @@ -239,6 +243,7 @@ impl AsSlice for MapIndexesMetadata { self.list.as_slice() } } + impl AsMutSlice for MapIndexesMetadata { type Entry = usize; /// Convert to a slice @@ -286,6 +291,7 @@ impl AsSlice for MapNoveltiesMetadata { self.list.as_slice() } } + impl AsMutSlice for MapNoveltiesMetadata { type Entry = usize; /// Convert to a slice @@ -294,6 +300,7 @@ impl AsMutSlice for MapNoveltiesMetadata { self.list.as_mut_slice() } } + impl MapNoveltiesMetadata { /// Creates a new [`struct@MapNoveltiesMetadata`] #[must_use] @@ -376,9 +383,7 @@ where /// The most common AFL-like feedback type #[derive(Clone, Debug)] -pub struct MapFeedback { - /// Indexes used in the last observation - indexes: bool, +pub struct MapFeedback { /// New indexes observed in the last observation novelties: Option>, /// Name identifier of this instance @@ -388,24 +393,25 @@ pub struct MapFeedback { /// Name of the feedback as shown in the `UserStats` stats_name: String, /// Phantom Data of Reducer - phantom: PhantomData<(N, O, R, S, T)>, + phantom: PhantomData<(C, N, O, R, S, T)>, } -impl UsesObserver for MapFeedback +impl UsesObserver for MapFeedback where S: UsesInput, - O: Observer, + C: AsRef + Observer, { - type Observer = O; + type Observer = C; } -impl Feedback for MapFeedback +impl Feedback for MapFeedback where N: IsNovel, O: MapObserver + for<'it> AsIter<'it, Item = T>, R: Reducer, S: State + HasNamedMetadata, T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static, + C: CanTrack + AsRef, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. @@ -461,7 +467,10 @@ where let meta = MapNoveltiesMetadata::new(novelties); testcase.add_metadata(meta); } - let observer = observers.match_name::(&self.observer_name).unwrap(); + let observer = observers + .match_name::(&self.observer_name) + .unwrap() + .as_ref(); let initial = observer.initial(); let map_state = state .named_metadata_map_mut() @@ -473,7 +482,7 @@ where } let history_map = map_state.history_map.as_mut_slice(); - if self.indexes { + if C::INDICES { let mut indices = Vec::new(); for (i, value) in observer @@ -540,11 +549,12 @@ where /// Specialize for the common coverage map size, maximization of u8s #[rustversion::nightly] -impl Feedback for MapFeedback +impl Feedback for MapFeedback where O: MapObserver + AsSlice, for<'it> O: AsIter<'it, Item = u8>, S: State + HasNamedMetadata, + C: CanTrack + AsRef, { #[allow(clippy::wrong_self_convention)] #[allow(clippy::needless_range_loop)] @@ -565,7 +575,10 @@ where let mut interesting = false; // TODO Replace with match_name_type when stable - let observer = observers.match_name::(&self.observer_name).unwrap(); + let observer = observers + .match_name::(&self.observer_name) + .unwrap() + .as_ref(); let map_state = state .named_metadata_map_mut() @@ -656,21 +669,17 @@ where } } -impl Named for MapFeedback { +impl Named for MapFeedback { #[inline] fn name(&self) -> &str { self.name.as_str() } } -impl HasObserverName for MapFeedback +impl HasObserverName for MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, - R: Reducer, - N: IsNovel, - O: MapObserver, - for<'it> O: AsIter<'it, Item = T>, - S: HasNamedMetadata, + O: Named, + C: AsRef, { #[inline] fn observer_name(&self) -> &str { @@ -682,7 +691,7 @@ fn create_stats_name(name: &str) -> String { name.to_lowercase() } -impl MapFeedback +impl MapFeedback where T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, @@ -690,13 +699,14 @@ where for<'it> O: AsIter<'it, Item = T>, N: IsNovel, S: UsesInput + HasNamedMetadata, + C: CanTrack + AsRef, { /// Create new `MapFeedback` #[must_use] - pub fn new(map_observer: &O) -> Self { + pub fn new(map_observer: &C) -> Self { + let map_observer = map_observer.as_ref(); Self { - indexes: false, - novelties: None, + novelties: if C::NOVELTIES { Some(vec![]) } else { None }, name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(), stats_name: create_stats_name(map_observer.name()), @@ -704,40 +714,14 @@ where } } - /// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties - #[must_use] - pub fn tracking(map_observer: &O, track_indexes: bool, track_novelties: bool) -> Self { - Self { - indexes: track_indexes, - novelties: if track_novelties { Some(vec![]) } else { None }, - name: map_observer.name().to_string(), - observer_name: map_observer.name().to_string(), - stats_name: create_stats_name(map_observer.name()), - phantom: PhantomData, - } - } - - /// Create new `MapFeedback` - #[must_use] - pub fn with_names(name: &'static str, observer_name: &'static str) -> Self { - Self { - indexes: false, - novelties: None, - name: name.to_string(), - observer_name: observer_name.to_string(), - stats_name: create_stats_name(name), - phantom: PhantomData, - } - } - /// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same /// feedback is needed twice, but with a different history. Using `new()` always results in the /// same name and therefore also the same history. #[must_use] - pub fn with_name(name: &'static str, map_observer: &O) -> Self { + pub fn with_name(name: &'static str, map_observer: &C) -> Self { + let map_observer = map_observer.as_ref(); Self { - indexes: false, - novelties: None, + novelties: if C::NOVELTIES { Some(vec![]) } else { None }, name: name.to_string(), observer_name: map_observer.name().to_string(), stats_name: create_stats_name(name), @@ -745,24 +729,6 @@ where } } - /// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties - #[must_use] - pub fn with_names_tracking( - name: &'static str, - observer_name: &'static str, - track_indexes: bool, - track_novelties: bool, - ) -> Self { - Self { - indexes: track_indexes, - novelties: if track_novelties { Some(vec![]) } else { None }, - observer_name: observer_name.to_string(), - stats_name: create_stats_name(name), - name: name.to_string(), - phantom: PhantomData, - } - } - #[allow(clippy::wrong_self_convention)] #[allow(clippy::needless_range_loop)] #[allow(clippy::trivially_copy_pass_by_ref)] @@ -780,7 +746,10 @@ where { let mut interesting = false; // TODO Replace with match_name_type when stable - let observer = observers.match_name::(&self.observer_name).unwrap(); + let observer = observers + .match_name::(&self.observer_name) + .unwrap() + .as_ref(); let map_state = state .named_metadata_map_mut() diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index a2d2435fa3e..b14d44dd0e9 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -80,10 +80,347 @@ fn hash_slice(slice: &[T]) -> u64 { hasher.finish() } +/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties. +/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to +/// ensure that edge metadata is recorded as is appropriate for the provided observer. +/// +/// If you get a type constraint failure for your map due to this type being unfulfilled, you must +/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at +/// the initialisation site of your map**. +/// +/// This trait allows various components which interact with map metadata to ensure that the +/// information they need is actually recorded by the map feedback. +/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]: +/// ``` +/// # use libafl::corpus::InMemoryCorpus; +/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata}; +/// use libafl::feedbacks::MaxMapFeedback; +/// # use libafl::inputs::BytesInput; +/// use libafl::observers::{StdMapObserver, CanTrack}; +/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}; +/// # use libafl::state::StdState; +/// # use libafl_bolts::serdeany::RegistryBuilder; +/// # +/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))] +/// # unsafe { MapFeedbackMetadata::::register() } +/// # #[cfg(not(feature = "std"))] +/// # #[no_mangle] +/// # pub extern "C" fn external_current_millis() -> u64 { 0 } +/// +/// use libafl_bolts::ownedref::OwnedMutSlice; +/// # use libafl_bolts::rands::StdRand; +/// +/// // initialise your map as necessary +/// let edges_observer = StdMapObserver::from_ownedref("edges", OwnedMutSlice::from(vec![0u8; 16])); +/// // inform the feedback to track indices (required by IndexesLenTimeMinimizerScheduler), but not novelties +/// // this *MUST* be done before it is passed to MaxMapFeedback! +/// let edges_observer = edges_observer.track_indices(); +/// +/// // init the feedback +/// let mut feedback = MaxMapFeedback::new(&edges_observer); +/// # +/// # // init the state +/// # let mut state = StdState::new( +/// # StdRand::with_seed(0), +/// # InMemoryCorpus::::new(), +/// # InMemoryCorpus::new(), +/// # &mut feedback, +/// # &mut () +/// # ).unwrap(); +/// # feedback.init_state(&mut state).unwrap(); +/// +/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); +/// # scheduler.cull(&state).unwrap(); +/// ``` +/// +/// [`MapObserver`] implementors: see [`StdMapObserver`] for an example implementation. +pub trait CanTrack { + /// The resulting type of enabling index tracking. + type WithIndexTracking: CanTrack; + /// The resulting type of enabling novelty tracking. + type WithNoveltiesTracking: CanTrack; + + /// Whether indices should be tracked for this [`MapObserver`]. + const INDICES: bool; + /// Whether novelties should be tracked for this [`MapObserver`]. + const NOVELTIES: bool; + + /// Convert this map observer into one that tracks indices. + fn track_indices(self) -> Self::WithIndexTracking; + /// Convert this map observer into one that tracks novelties. + fn track_novelties(self) -> Self::WithNoveltiesTracking; +} + +/// Struct which wraps [`MapObserver`] instances to explicitly give them tracking data. +/// +/// # Safety +/// +/// This is a bit of a magic structure. We pass it to the observer tuple as itself, but when its +/// referred to with `match_name`, there is a cast from this type to its inner type. This is +/// *guaranteed to be safe* by `#[repr(transparent)]`. +#[derive(Copy, Clone, Debug, Deserialize, Serialize)] +pub struct ExplicitTracking(T); + +impl CanTrack for ExplicitTracking { + type WithIndexTracking = ExplicitTracking; + type WithNoveltiesTracking = ExplicitTracking; + const INDICES: bool = ITH; + const NOVELTIES: bool = NTH; + + fn track_indices(self) -> Self::WithIndexTracking { + ExplicitTracking::(self.0) + } + + fn track_novelties(self) -> Self::WithNoveltiesTracking { + ExplicitTracking::(self.0) + } +} + +impl AsRef for ExplicitTracking { + fn as_ref(&self) -> &T { + &self.0 + } +} + +impl AsMut for ExplicitTracking { + fn as_mut(&mut self) -> &mut T { + &mut self.0 + } +} + +impl Named for ExplicitTracking +where + T: Named, +{ + fn name(&self) -> &str { + self.0.name() + } +} + +impl Observer for ExplicitTracking +where + S: UsesInput, + T: Observer, +{ + fn flush(&mut self) -> Result<(), Error> { + self.0.flush() + } + + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.0.pre_exec(state, input) + } + + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.0.post_exec(state, input, exit_kind) + } + + fn pre_exec_child(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { + self.0.pre_exec_child(state, input) + } + + fn post_exec_child( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.0.post_exec_child(state, input, exit_kind) + } + + fn observes_stdout(&self) -> bool { + self.0.observes_stdout() + } + + fn observes_stderr(&self) -> bool { + self.0.observes_stderr() + } + + fn observe_stdout(&mut self, stdout: &[u8]) { + self.0.observe_stdout(stdout); + } + + fn observe_stderr(&mut self, stderr: &[u8]) { + self.0.observe_stderr(stderr); + } +} + +impl DifferentialObserver + for ExplicitTracking +where + OTA: ObserversTuple, + OTB: ObserversTuple, + S: UsesInput, + T: DifferentialObserver, +{ + fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.as_mut().pre_observe_first(observers) + } + + fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> { + self.as_mut().post_observe_first(observers) + } + + fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.as_mut().pre_observe_second(observers) + } + + fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> { + self.as_mut().post_observe_second(observers) + } +} + +/// Module which holds the necessary functions and types for map-relevant macros, namely +/// [`crate::require_index_tracking`] and [`crate::require_novelties_tracking`]. +pub mod macros { + pub use const_format::{concatcp, str_repeat}; + pub use const_panic::{concat_panic, FmtArg}; + + /// Use in the constructor of your component which requires index tracking of a + /// [`super::MapObserver`]. See [`super::CanTrack`] for details. + /// + /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty + /// tracking, use this in your constructor: + /// ``` + /// # use libafl::observers::{MapObserver, CanTrack}; + /// # use libafl::require_index_tracking; + /// # use core::marker::PhantomData; + /// # + /// # struct MyCustomScheduler { + /// # phantom: PhantomData<(C, O)>, + /// # } + /// # + /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { + /// pub fn new(obs: &C) -> Self { + /// require_index_tracking!("MyCustomScheduler", C); + /// todo!("Construct your type") + /// } + /// } + /// ``` + #[macro_export] + macro_rules! require_index_tracking { + ($name: literal, $obs: ident) => { + struct SanityCheck { + phantom: ::core::marker::PhantomData, + } + + impl SanityCheck { + #[rustfmt::skip] + const MESSAGE: &'static str = { + const LINE_OFFSET: usize = line!().ilog10() as usize + 2; + const SPACING: &str = $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); + $crate::observers::map::macros::concatcp!( + "\n", + SPACING, "|\n", + SPACING, "= note: index tracking is required by ", $name, "\n", + SPACING, "= note: see the documentation of CanTrack for details\n", + SPACING, "|\n", + SPACING, "= hint: call `.track_indices()` on the map observer passed to ", $name, " at the point where it is defined\n", + SPACING, "|\n", + SPACING, "| ", + ) + }; + const TRACKING_SANITY: bool = { + if !O::INDICES { + panic!("{}", Self::MESSAGE) + } else { + true + } + }; + + #[inline(always)] + fn check_sanity() { + if !Self::TRACKING_SANITY { + unreachable!("{}", Self::MESSAGE); + } + } + } + SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map + }; + } + + /// Use in the constructor of your component which requires novelties tracking of a + /// [`super::MapObserver`]. See [`super::CanTrack`] for details on the concept. + /// + /// As an example, if you are developing the type `MyCustomScheduler` which requires novelty + /// tracking, use this in your constructor: + /// ``` + /// # use libafl::observers::{MapObserver, CanTrack}; + /// # use libafl::require_novelties_tracking; + /// # use core::marker::PhantomData; + /// # + /// # struct MyCustomScheduler { + /// # phantom: PhantomData<(C, O)>, + /// # } + /// # + /// impl MyCustomScheduler where O: MapObserver, C: CanTrack + AsRef { + /// pub fn new(obs: &C) -> Self { + /// require_novelties_tracking!("MyCustomScheduler", C); + /// todo!("Construct your type") + /// } + /// } + /// ``` + #[macro_export] + macro_rules! require_novelties_tracking { + ($name: literal, $obs: ident) => { + struct SanityCheck { + phantom: ::core::marker::PhantomData, + } + + impl SanityCheck { + #[rustfmt::skip] + const MESSAGE: &'static str = { + const LINE_OFFSET: usize = line!().ilog10() as usize + 2; + const SPACING: &str = + $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET); + $crate::observers::map::macros::concatcp!( + "\n", + SPACING, "|\n", + SPACING, "= note: novelty tracking is required by ", $name, "\n", + SPACING, "= note: see the documentation of CanTrack for details\n", + SPACING, "|\n", + SPACING, "= hint: call `.track_novelties()` on the map observer passed to ", $name, " at the point where it is defined\n", + SPACING, "|\n", + SPACING, "| ", + ) + }; + const TRACKING_SANITY: bool = { + if !O::NOVELTIES { + panic!("{}", Self::MESSAGE) + } else { + true + } + }; + + #[inline(always)] + fn check_sanity() { + if !Self::TRACKING_SANITY { + unreachable!("{}", Self::MESSAGE); + } + } + } + SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map + }; + } +} + /// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information /// +/// When referring to this type in a constraint (e.g. `O: MapObserver`), ensure that you only refer +/// to instances of a second type, e.g. `C: AsRef` or `A: AsMut`. Map observer instances are +/// passed around in a way that may be potentially wrapped by e.g. [`ExplicitTracking`] as a way to +/// encode metadata into the type. This is an unfortunate additional requirement that we can't get +/// around without specialization. +/// +/// See [`crate::require_index_tracking`] for an example of how to do so. +/// /// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize -pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned +pub trait MapObserver: + HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef + AsMut // where // for<'it> &'it Self: IntoIterator { @@ -118,6 +455,24 @@ pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned fn how_many_set(&self, indexes: &[usize]) -> usize; } +impl CanTrack for M +where + M: MapObserver, +{ + type WithIndexTracking = ExplicitTracking; + type WithNoveltiesTracking = ExplicitTracking; + const INDICES: bool = false; + const NOVELTIES: bool = false; + + fn track_indices(self) -> Self::WithIndexTracking { + ExplicitTracking::(self) + } + + fn track_novelties(self) -> Self::WithNoveltiesTracking { + ExplicitTracking::(self) + } +} + /// A Simple iterator calling `MapObserver::get` #[derive(Debug)] pub struct MapObserverSimpleIterator<'a, O> @@ -346,6 +701,24 @@ where } } +impl<'a, T, const DIFFERENTIAL: bool> AsRef for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsMut for StdMapObserver<'a, T, DIFFERENTIAL> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL> where T: Bounded @@ -455,6 +828,7 @@ where self.map.as_slice() } } + impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, @@ -830,6 +1204,24 @@ where } } +impl<'a, T, const N: usize> AsRef for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const N: usize> AsMut for ConstMapObserver<'a, T, N> +where + T: Default + Copy + 'static + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N> where T: Bounded @@ -922,6 +1314,7 @@ where self.map.as_slice() } } + impl<'a, T, const N: usize> AsMutSlice for ConstMapObserver<'a, T, N> where T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, @@ -1142,6 +1535,24 @@ where } } +impl<'a, T> AsRef for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + PartialEq + Bounded, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T> AsMut for VariableMapObserver<'a, T> +where + T: Default + Copy + 'static + Serialize + PartialEq + Bounded, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl<'a, T> MapObserver for VariableMapObserver<'a, T> where T: Bounded @@ -1243,6 +1654,7 @@ where &self.map.as_slice()[..cnt] } } + impl<'a, T> AsMutSlice for VariableMapObserver<'a, T> where T: 'static @@ -1305,8 +1717,8 @@ where /// Map observer with AFL-like hitcounts postprocessing /// -/// [`MapObserver`]s that are not slice-backed, -/// such as [`MultiMapObserver`], can use [`HitcountsIterableMapObserver`] instead. +/// [`MapObserver`]s that are not slice-backed, such as [`MultiMapObserver`], can use +/// [`HitcountsIterableMapObserver`] instead. #[derive(Serialize, Deserialize, Clone, Debug)] #[serde(bound = "M: serde::de::DeserializeOwned")] pub struct HitcountsMapObserver @@ -1396,6 +1808,24 @@ where } } +impl AsRef for HitcountsMapObserver +where + M: MapObserver, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for HitcountsMapObserver +where + M: MapObserver, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl MapObserver for HitcountsMapObserver where M: MapObserver, @@ -1478,7 +1908,7 @@ where impl HitcountsMapObserver where - M: Serialize + serde::de::DeserializeOwned, + M: MapObserver, { /// Creates a new [`MapObserver`] pub fn new(base: M) -> Self { @@ -1645,6 +2075,26 @@ where } } +impl AsRef for HitcountsIterableMapObserver +where + M: MapObserver, + for<'it> M: AsIterMut<'it, Item = u8>, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for HitcountsIterableMapObserver +where + M: MapObserver, + for<'it> M: AsIterMut<'it, Item = u8>, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl MapObserver for HitcountsIterableMapObserver where M: MapObserver, @@ -1714,6 +2164,7 @@ where self.base.as_slice() } } + impl AsMutSlice for HitcountsIterableMapObserver where M: MapObserver + AsMutSlice, @@ -1890,6 +2341,24 @@ where } } +impl<'a, T, const DIFFERENTIAL: bool> AsRef for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + Debug, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl<'a, T, const DIFFERENTIAL: bool> AsMut for MultiMapObserver<'a, T, DIFFERENTIAL> +where + T: 'static + Default + Copy + Serialize + Debug, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL> where T: 'static @@ -2245,6 +2714,24 @@ where } } +impl AsRef for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize, +{ + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for OwnedMapObserver +where + T: 'static + Default + Copy + Serialize, +{ + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl MapObserver for OwnedMapObserver where T: 'static diff --git a/libafl/src/schedulers/accounting.rs b/libafl/src/schedulers/accounting.rs index a3d7d05ec10..53becae593b 100644 --- a/libafl/src/schedulers/accounting.rs +++ b/libafl/src/schedulers/accounting.rs @@ -11,7 +11,7 @@ use crate::{ corpus::{Corpus, CorpusId}, feedbacks::MapIndexesMetadata, inputs::UsesInput, - observers::ObserversTuple, + observers::{CanTrack, ObserversTuple}, schedulers::{ minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, LenTimeMulTestcaseScore, Scheduler, @@ -106,7 +106,7 @@ impl TopAccountingMetadata { /// A minimizer scheduler using coverage accounting #[derive(Debug)] -pub struct CoverageAccountingScheduler<'a, CS> +pub struct CoverageAccountingScheduler<'a, CS, O> where CS: UsesState, CS::State: Debug, @@ -117,10 +117,11 @@ where CS, LenTimeMulTestcaseScore<::State>, MapIndexesMetadata, + O, >, } -impl<'a, CS> UsesState for CoverageAccountingScheduler<'a, CS> +impl<'a, CS, O> UsesState for CoverageAccountingScheduler<'a, CS, O> where CS: UsesState, CS::State: Debug, @@ -128,11 +129,12 @@ where type State = CS::State; } -impl<'a, CS> Scheduler for CoverageAccountingScheduler<'a, CS> +impl<'a, CS, O> Scheduler for CoverageAccountingScheduler<'a, CS, O> where CS: Scheduler, CS::State: HasCorpus + HasMetadata + HasRand + Debug, ::Input: HasLen, + O: CanTrack, { fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { self.update_accounting_score(state, idx)?; @@ -190,11 +192,12 @@ where } } -impl<'a, CS> CoverageAccountingScheduler<'a, CS> +impl<'a, CS, O> CoverageAccountingScheduler<'a, CS, O> where CS: Scheduler, CS::State: HasCorpus + HasMetadata + HasRand + Debug, ::Input: HasLen, + O: CanTrack, { /// Update the `Corpus` score #[allow(clippy::unused_self)] @@ -307,7 +310,9 @@ where /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. - pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { + /// + /// Provide the observer responsible for determining new indexes. + pub fn new(observer: &O, state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { match state.metadata_map().get::() { Some(meta) => { if meta.max_accounting.len() != accounting_map.len() { @@ -320,14 +325,17 @@ where } Self { accounting_map, - inner: MinimizerScheduler::new(base), + inner: MinimizerScheduler::new(observer, base), skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, } } /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// and has a non-default probability to skip non-faved Testcases using (`skip_non_favored_prob`). + /// + /// Provide the observer responsible for determining new indexes. pub fn with_skip_prob( + observer: &O, state: &mut CS::State, base: CS, skip_non_favored_prob: u64, @@ -345,7 +353,7 @@ where } Self { accounting_map, - inner: MinimizerScheduler::with_skip_prob(base, skip_non_favored_prob), + inner: MinimizerScheduler::with_skip_prob(observer, base, skip_non_favored_prob), skip_non_favored_prob, } } diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index c19959134f3..2c653b9ee95 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -12,7 +12,8 @@ use crate::{ corpus::{Corpus, CorpusId, Testcase}, feedbacks::MapIndexesMetadata, inputs::UsesInput, - observers::ObserversTuple, + observers::{CanTrack, ObserversTuple}, + require_index_tracking, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore}, state::{HasCorpus, HasRand, UsesState}, Error, HasMetadata, @@ -70,26 +71,27 @@ impl Default for TopRatedsMetadata { /// corpus that exercise all the requested features (e.g. all the coverage seen so far) /// prioritizing [`Testcase`]`s` using [`TestcaseScore`] #[derive(Debug, Clone)] -pub struct MinimizerScheduler { +pub struct MinimizerScheduler { base: CS, skip_non_favored_prob: u64, remove_metadata: bool, - phantom: PhantomData<(F, M)>, + phantom: PhantomData<(F, M, O)>, } -impl UsesState for MinimizerScheduler +impl UsesState for MinimizerScheduler where CS: UsesState, { type State = CS::State; } -impl RemovableScheduler for MinimizerScheduler +impl RemovableScheduler for MinimizerScheduler where CS: RemovableScheduler, F: TestcaseScore, M: AsSlice + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, + O: CanTrack, { /// Replaces the testcase at the given idx fn on_replace( @@ -191,12 +193,13 @@ where } } -impl Scheduler for MinimizerScheduler +impl Scheduler for MinimizerScheduler where CS: Scheduler, F: TestcaseScore, M: AsSlice + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, + O: CanTrack, { /// Called when a [`Testcase`] is added to the corpus fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> { @@ -246,12 +249,13 @@ where } } -impl MinimizerScheduler +impl MinimizerScheduler where CS: Scheduler, F: TestcaseScore, M: AsSlice + SerdeAny + HasRefCnt, CS::State: HasCorpus + HasMetadata + HasRand, + O: CanTrack, { /// Update the [`Corpus`] score using the [`MinimizerScheduler`] #[allow(clippy::unused_self)] @@ -371,7 +375,10 @@ where /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// This will remove the metadata `M` when it is no longer needed, after consumption. This might /// for example be a `MapIndexesMetadata`. - pub fn new(base: CS) -> Self { + /// + /// When calling, pass the edges observer which will provided the indexes to minimize over. + pub fn new(_observer: &O, base: CS) -> Self { + require_index_tracking!("MinimizerScheduler", O); Self { base, skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, @@ -383,7 +390,10 @@ where /// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`] /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// This method will prevent the metadata `M` from being removed at the end of scoring. - pub fn non_metadata_removing(base: CS) -> Self { + /// + /// When calling, pass the edges observer which will provided the indexes to minimize over. + pub fn non_metadata_removing(_observer: &O, base: CS) -> Self { + require_index_tracking!("MinimizerScheduler", O); Self { base, skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, @@ -394,7 +404,10 @@ where /// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`] /// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`). - pub fn with_skip_prob(base: CS, skip_non_favored_prob: u64) -> Self { + /// + /// When calling, pass the edges observer which will provided the indexes to minimize over. + pub fn with_skip_prob(_observer: &O, base: CS, skip_non_favored_prob: u64) -> Self { + require_index_tracking!("MinimizerScheduler", O); Self { base, skip_non_favored_prob, @@ -405,10 +418,14 @@ where } /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`. -pub type LenTimeMinimizerScheduler = - MinimizerScheduler::State>, M>; +pub type LenTimeMinimizerScheduler = + MinimizerScheduler::State>, M, O>; /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s` /// that exercise all the entries registered in the [`MapIndexesMetadata`]. -pub type IndexesLenTimeMinimizerScheduler = - MinimizerScheduler::State>, MapIndexesMetadata>; +pub type IndexesLenTimeMinimizerScheduler = MinimizerScheduler< + CS, + LenTimeMulTestcaseScore<::State>, + MapIndexesMetadata, + O, +>; diff --git a/libafl/src/schedulers/mod.rs b/libafl/src/schedulers/mod.rs index bbc70763358..e026d24e1a7 100644 --- a/libafl/src/schedulers/mod.rs +++ b/libafl/src/schedulers/mod.rs @@ -66,10 +66,11 @@ where } /// Defines the common metadata operations for the AFL-style schedulers -pub trait AflScheduler: Scheduler +pub trait AflScheduler: Scheduler where Self::State: HasCorpus + HasMetadata + HasTestcase, O: MapObserver, + C: AsRef, { /// Return the last hash fn last_hash(&self) -> usize; @@ -117,8 +118,9 @@ where OT: ObserversTuple, { let observer = observers - .match_name::(self.map_observer_name()) - .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; + .match_name::(self.map_observer_name()) + .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref(); let mut hash = observer.hash() as usize; diff --git a/libafl/src/schedulers/powersched.rs b/libafl/src/schedulers/powersched.rs index 1679eee6f1e..e0b8e185069 100644 --- a/libafl/src/schedulers/powersched.rs +++ b/libafl/src/schedulers/powersched.rs @@ -6,6 +6,7 @@ use alloc::{ }; use core::{marker::PhantomData, time::Duration}; +use libafl_bolts::Named; use serde::{Deserialize, Serialize}; use crate::{ @@ -170,24 +171,25 @@ pub enum PowerSchedule { /// Note that this corpus is merely holding the metadata necessary for the power calculation /// and here we DON'T actually calculate the power (we do it in the stage) #[derive(Clone, Debug)] -pub struct PowerQueueScheduler { +pub struct PowerQueueScheduler { strat: PowerSchedule, map_observer_name: String, last_hash: usize, - phantom: PhantomData<(O, S)>, + phantom: PhantomData<(C, O, S)>, } -impl UsesState for PowerQueueScheduler +impl UsesState for PowerQueueScheduler where S: State, { type State = S; } -impl RemovableScheduler for PowerQueueScheduler +impl RemovableScheduler for PowerQueueScheduler where S: State + HasTestcase + HasMetadata + HasCorpus, O: MapObserver, + C: AsRef, { /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` fn on_remove( @@ -210,10 +212,11 @@ where } } -impl AflScheduler for PowerQueueScheduler +impl AflScheduler for PowerQueueScheduler where S: HasCorpus + HasMetadata + HasTestcase + State, O: MapObserver, + C: AsRef, { fn last_hash(&self) -> usize { self.last_hash @@ -228,10 +231,11 @@ where } } -impl Scheduler for PowerQueueScheduler +impl Scheduler for PowerQueueScheduler where S: HasCorpus + HasMetadata + HasTestcase + State, O: MapObserver, + C: AsRef, { /// Called when a [`Testcase`] is added to the corpus fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { @@ -287,14 +291,15 @@ where } } -impl PowerQueueScheduler +impl PowerQueueScheduler where S: HasMetadata, O: MapObserver, + C: AsRef + Named, { /// Create a new [`PowerQueueScheduler`] #[must_use] - pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self { + pub fn new(state: &mut S, map_observer: &C, strat: PowerSchedule) -> Self { if !state.has_metadata::() { state.add_metadata::(SchedulerMetadata::new(Some(strat))); } diff --git a/libafl/src/schedulers/weighted.rs b/libafl/src/schedulers/weighted.rs index e1cf27cb53b..4b5ebd66859 100644 --- a/libafl/src/schedulers/weighted.rs +++ b/libafl/src/schedulers/weighted.rs @@ -1,11 +1,11 @@ -//! The queue corpus scheduler with weighted queue item selection from aflpp (`https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32`) +//! The queue corpus scheduler with weighted queue item selection [from AFL++](https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32). //! This queue corpus scheduler needs calibration stage. use alloc::string::{String, ToString}; use core::marker::PhantomData; use hashbrown::HashMap; -use libafl_bolts::rands::Rand; +use libafl_bolts::{rands::Rand, Named}; use serde::{Deserialize, Serialize}; use crate::{ @@ -92,29 +92,30 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata); /// A corpus scheduler using power schedules with weighted queue item selection algo. #[derive(Clone, Debug)] -pub struct WeightedScheduler { +pub struct WeightedScheduler { table_invalidated: bool, strat: Option, map_observer_name: String, last_hash: usize, - phantom: PhantomData<(F, O, S)>, + phantom: PhantomData<(C, F, O, S)>, } -impl WeightedScheduler +impl WeightedScheduler where F: TestcaseScore, O: MapObserver, S: HasCorpus + HasMetadata + HasRand, + C: AsRef + Named, { /// Create a new [`WeightedScheduler`] without any power schedule #[must_use] - pub fn new(state: &mut S, map_observer: &O) -> Self { + pub fn new(state: &mut S, map_observer: &C) -> Self { Self::with_schedule(state, map_observer, None) } /// Create a new [`WeightedScheduler`] #[must_use] - pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option) -> Self { + pub fn with_schedule(state: &mut S, map_observer: &C, strat: Option) -> Self { let _ = state.metadata_or_insert_with(|| SchedulerMetadata::new(strat)); let _ = state.metadata_or_insert_with(WeightedScheduleMetadata::new); @@ -218,18 +219,19 @@ where } } -impl UsesState for WeightedScheduler +impl UsesState for WeightedScheduler where S: State, { type State = S; } -impl RemovableScheduler for WeightedScheduler +impl RemovableScheduler for WeightedScheduler where F: TestcaseScore, O: MapObserver, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, + C: AsRef + Named, { /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` fn on_remove( @@ -254,11 +256,12 @@ where } } -impl AflScheduler for WeightedScheduler +impl AflScheduler for WeightedScheduler where F: TestcaseScore, - S: HasCorpus + HasMetadata + HasTestcase + HasRand + State, O: MapObserver, + S: HasCorpus + HasMetadata + HasTestcase + HasRand + State, + C: AsRef + Named, { fn last_hash(&self) -> usize { self.last_hash @@ -273,11 +276,12 @@ where } } -impl Scheduler for WeightedScheduler +impl Scheduler for WeightedScheduler where F: TestcaseScore, O: MapObserver, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, + C: AsRef + Named, { /// Called when a [`Testcase`] is added to the corpus fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> { @@ -356,5 +360,5 @@ where } } -/// The standard corpus weight, same as aflpp -pub type StdWeightedScheduler = WeightedScheduler, O, S>; +/// The standard corpus weight, same as in `AFL++` +pub type StdWeightedScheduler = WeightedScheduler, O, S>; diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index e6222a8f177..2f4b4c3c389 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -64,31 +64,32 @@ impl UnstableEntriesMetadata { /// The calibration stage will measure the average exec time and the target's stability for this input. #[derive(Clone, Debug)] -pub struct CalibrationStage { +pub struct CalibrationStage { map_observer_name: String, map_name: String, stage_max: usize, /// If we should track stability track_stability: bool, restart_helper: ExecutionCountRestartHelper, - phantom: PhantomData<(O, OT, S)>, + phantom: PhantomData<(C, O, OT, S)>, } const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1 -impl UsesState for CalibrationStage +impl UsesState for CalibrationStage where S: State, { type State = S; } -impl Stage for CalibrationStage +impl Stage for CalibrationStage where E: Executor + HasObservers, EM: EventFirer, O: MapObserver, + C: AsRef, for<'de> ::Entry: Serialize + Deserialize<'de> + 'static, OT: ObserversTuple, E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions, @@ -147,8 +148,9 @@ where let map_first = &executor .observers() - .match_name::(&self.map_observer_name) + .match_name::(&self.map_observer_name) .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref() .to_vec(); let mut unstable_entries: Vec = vec![]; @@ -190,8 +192,9 @@ where if self.track_stability { let map = &executor .observers() - .match_name::(&self.map_observer_name) + .match_name::(&self.map_observer_name) .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref() .to_vec(); let history_map = &mut state @@ -246,8 +249,9 @@ where if state.has_metadata::() { let map = executor .observers() - .match_name::(&self.map_observer_name) - .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; + .match_name::(&self.map_observer_name) + .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref(); let mut bitmap_size = map.count_bytes(); assert!(bitmap_size != 0); @@ -335,9 +339,10 @@ where } } -impl CalibrationStage +impl CalibrationStage where O: MapObserver, + C: AsRef, OT: ObserversTuple, S: HasCorpus + HasMetadata + HasNamedMetadata, { @@ -345,8 +350,9 @@ where #[must_use] pub fn new(map_feedback: &F) -> Self where - F: HasObserverName + Named + UsesObserver, + F: HasObserverName + Named + UsesObserver, for<'it> O: AsIter<'it, Item = O::Entry>, + C: AsRef, { Self { map_observer_name: map_feedback.observer_name().to_string(), @@ -362,8 +368,9 @@ where #[must_use] pub fn ignore_stability(map_feedback: &F) -> Self where - F: HasObserverName + Named + UsesObserver, + F: HasObserverName + Named + UsesObserver, for<'it> O: AsIter<'it, Item = O::Entry>, + C: AsRef, { Self { map_observer_name: map_feedback.observer_name().to_string(), diff --git a/libafl/src/stages/colorization.rs b/libafl/src/stages/colorization.rs index 8df70ff7267..d3a4ff5b34c 100644 --- a/libafl/src/stages/colorization.rs +++ b/libafl/src/stages/colorization.rs @@ -54,20 +54,20 @@ impl Ord for Earlier { /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct ColorizationStage { +pub struct ColorizationStage { map_observer_name: String, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, O, Z)>, + phantom: PhantomData<(C, E, EM, O, E, Z)>, } -impl UsesState for ColorizationStage +impl UsesState for ColorizationStage where E: UsesState, { type State = E::State; } -impl Named for ColorizationStage +impl Named for ColorizationStage where E: UsesState, { @@ -76,13 +76,14 @@ where } } -impl Stage for ColorizationStage +impl Stage for ColorizationStage where EM: UsesState + EventFirer, E: HasObservers + Executor, E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata, E::Input: HasBytesVec, O: MapObserver, + C: AsRef + Named, Z: UsesState, { #[inline] @@ -150,10 +151,11 @@ impl TaintMetadata { libafl_bolts::impl_serdeany!(TaintMetadata); -impl ColorizationStage +impl ColorizationStage where EM: UsesState + EventFirer, O: MapObserver, + C: AsRef + Named, E: HasObservers + Executor, E::State: HasCorpus + HasMetadata + HasRand, E::Input: HasBytesVec, @@ -297,9 +299,9 @@ where #[must_use] /// Creates a new [`ColorizationStage`] - pub fn new(map_observer_name: &O) -> Self { + pub fn new(map_observer: &C) -> Self { Self { - map_observer_name: map_observer_name.name().to_string(), + map_observer_name: map_observer.name().to_string(), phantom: PhantomData, } } @@ -319,8 +321,9 @@ where let observer = executor .observers() - .match_name::(name) - .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; + .match_name::(name) + .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref(); let hash = observer.hash() as usize; diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index 180891baca5..f27d9ba3eb5 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -14,7 +14,8 @@ use crate::{ feedbacks::map::MapNoveltiesMetadata, inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput}, mark_feature_time, - observers::{MapObserver, ObserversTuple}, + observers::{CanTrack, MapObserver, ObserversTuple}, + require_novelties_tracking, stages::{RetryRestartHelper, Stage}, start_timer, state::{HasCorpus, HasExecutions, UsesState}, @@ -41,19 +42,19 @@ fn find_next_char(list: &[Option], mut idx: usize, ch: u8) -> usize { /// A stage that runs a tracer executor #[derive(Clone, Debug)] -pub struct GeneralizationStage { +pub struct GeneralizationStage { map_observer_name: String, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, O, OT, Z)>, + phantom: PhantomData<(C, EM, O, OT, Z)>, } -impl Named for GeneralizationStage { +impl Named for GeneralizationStage { fn name(&self) -> &str { "GeneralizationStage" } } -impl UsesState for GeneralizationStage +impl UsesState for GeneralizationStage where EM: UsesState, EM::State: UsesInput, @@ -61,9 +62,10 @@ where type State = EM::State; } -impl Stage for GeneralizationStage +impl Stage for GeneralizationStage where O: MapObserver, + C: CanTrack + AsRef, E: Executor + HasObservers, E::Observers: ObserversTuple, E::State: @@ -331,18 +333,20 @@ where } } -impl GeneralizationStage +impl GeneralizationStage where EM: UsesState, O: MapObserver, + C: CanTrack + AsRef, OT: ObserversTuple, EM::State: UsesInput + HasExecutions + HasMetadata + HasCorpus, { /// Create a new [`GeneralizationStage`]. #[must_use] - pub fn new(map_observer: &O) -> Self { + pub fn new(map_observer: &C) -> Self { + require_novelties_tracking!("GeneralizationStage", C); Self { - map_observer_name: map_observer.name().to_string(), + map_observer_name: map_observer.as_ref().name().to_string(), phantom: PhantomData, } } @@ -387,8 +391,9 @@ where let cnt = executor .observers() - .match_name::(&self.map_observer_name) + .match_name::(&self.map_observer_name) .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? + .as_ref() .how_many_set(novelties); Ok(cnt == novelties.len()) diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index f8c8228bc59..fcb9050baf8 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -239,7 +239,7 @@ impl SyncFromBrokerMetadata { /// A stage that loads testcases from disk to sync with other fuzzers such as AFL++ #[derive(Debug)] -pub struct SyncFromBrokerStage +pub struct SyncFromBrokerStage where SP: ShMemProvider + 'static, S: UsesInput, @@ -247,10 +247,10 @@ where ICB: InputConverter, DI: Input, { - client: LlmpEventConverter, + client: LlmpEventConverter, } -impl UsesState for SyncFromBrokerStage +impl UsesState for SyncFromBrokerStage where SP: ShMemProvider + 'static, S: State, @@ -261,7 +261,7 @@ where type State = S; } -impl Stage for SyncFromBrokerStage +impl Stage for SyncFromBrokerStage where EM: UsesState + EventFirer, S: State + HasExecutions + HasCorpus + HasRand + HasMetadata + HasTestcase, @@ -343,7 +343,7 @@ where } } -impl SyncFromBrokerStage +impl SyncFromBrokerStage where SP: ShMemProvider + 'static, S: UsesInput, @@ -353,7 +353,7 @@ where { /// Creates a new [`SyncFromBrokerStage`] #[must_use] - pub fn new(client: LlmpEventConverter) -> Self { + pub fn new(client: LlmpEventConverter) -> Self { Self { client } } } diff --git a/libafl_bolts/README.md b/libafl_bolts/README.md index eb73f112a09..d29ef592088 100644 --- a/libafl_bolts/README.md +++ b/libafl_bolts/README.md @@ -28,7 +28,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su Even though we will gladly assist you in finishing up your PR, try to - keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26)) -- run `cargo fmt` on your code before pushing +- run `cargo nightly fmt` on your code before pushing - check the output of `cargo clippy --all` or `./clippy.sh` - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/corpus.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/corpus.rs index 8ac02e541bd..20f0ad30925 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/corpus.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/corpus.rs @@ -189,9 +189,7 @@ where match self._get(id, &self.mapping.enabled) { Ok(input) => Ok(input), Err(Error::KeyNotFound(..)) => return self._get(id, &self.mapping.disabled), - Err(e) => { - Err(e) - } + Err(e) => Err(e), } } fn current(&self) -> &Option { @@ -362,7 +360,7 @@ where fn get_from_all(&self, id: CorpusId) -> Result<&RefCell>, Error> { self.get(id) } - + // This just calls Self::nth as ArtifactCorpus disregards disabled entries fn nth_from_all(&self, nth: usize) -> CorpusId { self.nth(nth) diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/feedbacks.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/feedbacks.rs index 98e3af85555..f655ae3866b 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/feedbacks.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/feedbacks.rs @@ -171,4 +171,4 @@ where } } -pub type ShrinkMapFeedback = MinMapFeedback, S, usize>; +pub type ShrinkMapFeedback = MinMapFeedback, S, usize>; diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs index c7a07e55386..294be68f67a 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs @@ -168,7 +168,7 @@ macro_rules! fuzz_with { I2SRandReplace, StdScheduledMutator, StringCategoryRandMutator, StringSubcategoryRandMutator, StringCategoryTokenReplaceMutator, StringSubcategoryTokenReplaceMutator, Tokens, tokens_mutations }, - observers::{stacktrace::BacktraceObserver, TimeObserver}, + observers::{stacktrace::BacktraceObserver, TimeObserver, CanTrack}, schedulers::{ IndexesLenTimeMinimizerScheduler, powersched::PowerSchedule, PowerQueueScheduler, }, @@ -198,7 +198,7 @@ macro_rules! fuzz_with { let grimoire_metadata = should_use_grimoire(&mut state, &$options, &mutator_status)?; let grimoire = grimoire_metadata.should(); - let edges_observer = edge_maker(); + let edges_observer = edge_maker().track_indices().track_novelties(); let size_edges_observer = MappedEdgeMapObserver::new(edge_maker(), SizeValueObserver::default()); let keep_observer = LibfuzzerKeepFeedback::new(); @@ -220,8 +220,8 @@ macro_rules! fuzz_with { ); // New maximization map feedback linked to the edges observer - let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); - let shrinking_map_feedback = ShrinkMapFeedback::tracking(&size_edges_observer, false, false); + let map_feedback = MaxMapFeedback::new(&edges_observer); + let shrinking_map_feedback = ShrinkMapFeedback::new(&size_edges_observer); // Set up a generalization stage for grimoire let generalization = GeneralizationStage::new(&edges_observer); @@ -412,7 +412,7 @@ macro_rules! fuzz_with { let grimoire = IfStage::new(|_, _, _, _| Ok(grimoire.into()), (StdMutationalStage::transforming(grimoire_mutator), ())); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST)); + let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST)); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/merge.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/merge.rs index cfe6cdf5992..1601cfa1dc0 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/merge.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/merge.rs @@ -105,7 +105,7 @@ pub fn merge( let edges_observer = MappedEdgeMapObserver::new(edges_observer, SizeTimeValueObserver::new(time)); - let map_feedback = MinMapFeedback::tracking(&edges_observer, false, true); + let map_feedback = MinMapFeedback::new(&edges_observer); // Create an OOM observer to monitor if an OOM has occurred let oom_observer = OomObserver::new(options.rss_limit(), options.malloc_limit()); diff --git a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs index 22ada45c5a8..8e9a8871439 100644 --- a/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs +++ b/libafl_libfuzzer/libafl_libfuzzer_runtime/src/observers.rs @@ -55,6 +55,18 @@ where } } +impl AsRef for MappedEdgeMapObserver { + fn as_ref(&self) -> &Self { + self + } +} + +impl AsMut for MappedEdgeMapObserver { + fn as_mut(&mut self) -> &mut Self { + self + } +} + impl HasLen for MappedEdgeMapObserver where M: HasLen, diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index a9fe5289594..0f60f63262c 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -15,7 +15,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::Tokens, }, - observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::StdMutationalStage, state::{HasCorpus, StdState}, @@ -126,8 +126,10 @@ impl<'a> ForkserverBytesCoverageSugar<'a> { std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}")); // Create an observation channel using the coverage map - let edges_observer = - unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map)) }; + let edges_observer = unsafe { + HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map)) + .track_indices() + }; // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -136,7 +138,7 @@ impl<'a> ForkserverBytesCoverageSugar<'a> { // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -164,7 +166,8 @@ impl<'a> ForkserverBytesCoverageSugar<'a> { let mut tokens = Tokens::new(); // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index 7a7fab47e74..f0cdb432705 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -18,7 +18,7 @@ use libafl::{ scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, token_mutations::{I2SRandReplace, Tokens}, }, - observers::{HitcountsMapObserver, TimeObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -143,7 +143,8 @@ where _core_id| { // Create an observation channel using the coverage map let edges_observer = - HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); + HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }) + .track_indices(); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); @@ -154,7 +155,7 @@ where // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -186,7 +187,8 @@ where } // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 376bfd1ca7a..0e144549e97 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -21,7 +21,7 @@ use libafl::{ token_mutations::Tokens, I2SRandReplace, }, - observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, stages::{ShadowTracingStage, StdMutationalStage}, state::{HasCorpus, StdState}, @@ -156,6 +156,7 @@ where edges_map_mut_slice(), addr_of_mut!(edges::MAX_EDGES_NUM), )) + .track_indices() }; // Create an observation channel to keep track of the execution time @@ -168,7 +169,7 @@ where // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::tracking(&edges_observer, true, false), + MaxMapFeedback::new(&edges_observer), // Time feedback, this one does not need a feedback state TimeFeedback::with_observer(&time_observer) ); @@ -200,7 +201,8 @@ where } // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); + let scheduler = + IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index 96751eda57c..cf6b446b804 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -159,6 +159,18 @@ mod observers { } } + impl AsRef for CountersMultiMapObserver { + fn as_ref(&self) -> &Self { + self + } + } + + impl AsMut for CountersMultiMapObserver { + fn as_mut(&mut self) -> &mut Self { + self + } + } + impl MapObserver for CountersMultiMapObserver { type Entry = u8; diff --git a/scripts/build_all_fuzzers.sh b/scripts/build_all_fuzzers.sh new file mode 100755 index 00000000000..08c59bfa109 --- /dev/null +++ b/scripts/build_all_fuzzers.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +cd "$SCRIPT_DIR/.." || exit 1 +# TODO: This should be rewritten in rust, a Makefile, or some platform-independent language + +if [[ -z "${RUN_ON_CI}" ]]; then + fuzzers=$(find ./fuzzers -mindepth 1 -maxdepth 1 -type d) + backtrace_fuzzers=$(find ./fuzzers/backtrace_baby_fuzzers -mindepth 1 -maxdepth 1 -type d) +else + cargo build -p build_and_test_fuzzers + fuzzers=$(cargo run -p build_and_test_fuzzers -- "remotes/origin/main" "HEAD^") + backtrace_fuzzers="" + export PROFILE=dev + export PROFILE_DIR=debug +fi + +fuzzers=$(echo "$fuzzers" | tr ' ' '\n') +backtrace_fuzzers=$(echo "$backtrace_fuzzers" | tr ' ' '\n') + +libafl=$(pwd) + +# build with a shared target dir for all fuzzers. this should speed up +# compilation a bit, and allows for easier artifact management (caching and +# cargo clean). +export CARGO_TARGET_DIR="$libafl/target" +mkdir -p "$CARGO_TARGET_DIR" + +git submodule init && git submodule update + +# override default profile settings for speed +# export RUSTFLAGS="-C prefer-dynamic" +for profile in DEV RELEASE; # loop for all profiles +do + export CARGO_PROFILE_"$profile"_OPT_LEVEL=z # optimize for size + # runs into shared target dir bug: + # [pid 351769] openat(AT_FDCWD, "LibAFL/target/release/deps/libc-dbff77a14da5d893.libc.5deb7d4a-cgu.0.rcgu.dwo", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) + # error: failed to build archive: No such file or directory + # export CARGO_PROFILE_"$profile"_SPLIT_DEBUGINFO=unpacked # minimize debug info + # export CARGO_PROFILE_"$profile"_PANIC=abort + # export CARGO_PROFILE_"$profile"_INCREMENTAL=true +done + +# shellcheck disable=SC2116 +for fuzzer in $(echo "$fuzzers" "$backtrace_fuzzers"); +do + # skip nyx test on non-linux platforms + if [[ $fuzzer == *"nyx_"* ]]; then + continue + fi + + cd "$fuzzer" || exit 1 + # Clippy checks + echo "[*] Checking fmt for $fuzzer" + cargo +nightly fmt --all || exit 1 + + if [ -e ./Makefile.toml ]; then + echo "[*] Building $fuzzer" + cargo make build || exit 1 + echo "[+] Done building $fuzzer" + else + echo "[*] Building $fuzzer" + cargo build || exit 1 + echo "[+] Done building $fuzzer" + fi + + # no cleaning -- this is a local test, we want to cache here + cd "$libafl" || exit 1 + echo "" +done